繁体   English   中英

使用一个 function 的推断通用参数类型来键入其他函数

[英]Use inferred generic param type of one function to type other functions

我正在构建一个 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 function 引用未在Schema.render中注册的类型。

在上面的示例中, fields基本上应该是以下类型: Record<string, Scalars | 'User' | 'Post' | 'Blog' Record<string, Scalars | 'User' | 'Post' | 'Blog' Record<string, Scalars | 'User' | 'Post' | 'Blog' ,其中User | Post | Blog User | Post | Blog 从传递给s.render的节点推断User | Post | Blog

为此,我想推断传递给render function 的节点的名称,以便键入Schema.createNode的参数fields的值。

不幸的是,如果在 function 级别上声明,generics 仅由 function 参数捕获,如果在接口级别上声明则不会捕获(这是有道理的)。

如何重用s.render<T extends Node[]>(nodes: T)的推断泛型来键入 function createNode(name: string, fields: AllTypes<T>)其中T是在两个功能?

有没有办法使这项工作? (即使 API 略有不同)

谢谢

我不认为你可以让它与多个电话一起工作。 最好的解决方案是创建一个 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM