我正在构建一个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.render
函数中未在Schema.createNode
中注册的类型。
在上面的示例中,fields
的类型应该基本上是:Record<string, Scalars | 'User' | 'Post' | 'Blog'
,其中User | Post | Blog
是从传递给s.render
的节点推断出来的。
为此,我想推断传递给render
函数的节点的名称,以便键入fields
的参数Schema.createNode
的值。 / p>
不幸的是,泛型仅在函数级别上声明时才被函数参数捕获,而在接口级别上声明时则不被捕获。
如何重用s.render<T extends Node[]>(nodes: T)
的推断泛型来键入函数createNode(name: string, fields: AllTypes<T>)
,其中T
是两个函数之间共享的相同推断类型?
有没有办法使这项工作有效? (即使API稍有不同)
谢谢?
答案 0 :(得分:0)
我认为您无法将其用于多个呼叫。最有效的解决方案是创建一个将模式定义作为参数的类,然后将整个对象作为一个整体进行检查:
interface Node<T extends string = string> {
name: T;
}
type Scalars = 'Int' | 'Boolean' | 'String'
type AllTypes<T extends Record<keyof T, any>> = keyof T | Scalars
type Values<T> = T[keyof T]
type SchemNodes<T extends Record<keyof T, Record<string, AllTypes<T>>>> =
{ [P in Extract<keyof T, string>]: Node<P> }
class Schema<T extends Record<keyof T, Record<string, AllTypes<T>>>> {
constructor(types: T) { }
getNodes(): SchemNodes<T> {
return null!;
}
renderTypes(types: Array<Values<SchemNodes<T>>>) { }
}
const s = new Schema({
"User": { posts: "Post" },
"Blog": { users: "User" },
// "Comment": {},
"Post": { title: "String", comments: 'Comment' }
})
const { Blog, Post, User } = s.getNodes();