【发布时间】:2020-01-24 19:12:09
【问题描述】:
我正在构建一个 API 来呈现架构图。
这是它的样子(超简化)
interface Node {
name: string;
}
type NodeNames<T extends Node[]> = T[number]["name"]; // All node names as union of string literal
type Scalars = 'Int' | 'Boolean' | 'String'
type AllTypes<T extends Node[]> = NodeNames<T> | Scalars
interface Schema<T extends Node[]> {
createNode(name: String, fields: Record<string, AllTypes<T>>): Node;
render(types: T[]): string;
}
const s: Schema = { // generic not captured => "TypeError: Generic type 'Schema<T>' requires 1 type"
render(types) {
// print types
return ''
},
createNode(name, fields) {
return { name, fields };
}
};
const Blog = s.createNode("Blog", { users: "User" });
const User = s.createNode("User", { posts: "Post" });
const Post = s.createNode("Post", { title: "String", comments: 'Comment' }); // <== Expected type error because 'Comment' node doesn't exist
s.render([Blog, User, Post]);
我想确保不能从 Schema.createNode 函数引用未在 Schema.render 中注册的类型。
在上面的示例中,fields 基本上应该是以下类型:Record<string, Scalars | 'User' | 'Post' | 'Blog',其中User | Post | Blog 是从传递给s.render 的节点推断出来的
为此,我想推断传递给render 函数的节点的名称,以便输入Schema.createNode 的参数fields 的值。
不幸的是,泛型只有在函数级别声明时才会被函数参数捕获,而在接口级别声明时不会被捕获(这是有道理的)。
如何重用 s.render<T extends Node[]>(nodes: T) 的推断泛型来键入函数 createNode(name: string, fields: AllTypes<T>),其中 T 是两个函数之间共享的相同推断类型?
有没有办法让它工作? (即使 API 略有不同)
谢谢????
【问题讨论】:
-
您创建了
const s类型的Schema,而不是给它一个它需要的类型参数。它不会以Schema<Any>之类的东西结束,所以createNode对其fields参数没有任何类型限制? -
没有,上面的代码有类型错误。正如主题中所说,接口泛型不是由一个接口中的函数参数捕获的,这是有道理的,否则一个接口的任何函数都可能改变其泛型类型
标签: typescript typescript-typings typescript-generics