[英]Use inferred generic param type of one function to type other functions
I'm building an API to render a schema graph.我正在构建一个 API 来呈现模式图。
Here's what it looks like (ultra-simplified)这是它的样子(超简化)
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]);
I would like to make sure that one cannot reference a type that wasn't registered in the Schema.render
from the Schema.createNode
function.我想确保不能从
Schema.createNode
function 引用未在Schema.render
中注册的类型。
In the example above, fields
should basically be of type: Record<string, Scalars | 'User' | 'Post' | 'Blog'
在上面的示例中,
fields
基本上应该是以下类型: Record<string, Scalars | 'User' | 'Post' | 'Blog'
Record<string, Scalars | 'User' | 'Post' | 'Blog'
Record<string, Scalars | 'User' | 'Post' | 'Blog'
, where User | Post | Blog
Record<string, Scalars | 'User' | 'Post' | 'Blog'
,其中User | Post | Blog
User | Post | Blog
User | Post | Blog
is inferred from the nodes passed to s.render
从传递给
s.render
的节点推断User | Post | Blog
To do that, I'd like to infer the names of the nodes passed to the render
function, in order to type the values of the param fields
of Schema.createNode
.为此,我想推断传递给
render
function 的节点的名称,以便键入Schema.createNode
的参数fields
的值。
Unfortunately, generics are only captured by function parameters if declared on a function level, and not if declared on an interface level (which makes sense).不幸的是,如果在 function 级别上声明,generics 仅由 function 参数捕获,如果在接口级别上声明则不会捕获(这是有道理的)。
How can I reuse the inferred generic of s.render<T extends Node[]>(nodes: T)
to type the function createNode(name: string, fields: AllTypes<T>)
where T
is the same inferred type shared between the two functions?如何重用
s.render<T extends Node[]>(nodes: T)
的推断泛型来键入 function createNode(name: string, fields: AllTypes<T>)
其中T
是在两个功能?
Is there a way to make this work?有没有办法使这项工作? (even with a slightly different API)
(即使 API 略有不同)
Thanks谢谢
I don't think you can get this to work with multiple calls.我不认为你可以让它与多个电话一起工作。 The solution that woks best would be to create a class that takes the schema definitions as an argument and check the whole object as a whole:
最好的解决方案是创建一个 class ,它将模式定义作为参数并检查整个 object 作为一个整体:
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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.