Я создаю 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
, чтобы ввести значенияparam fields
из Schema.createNode
.
К сожалению, дженерики фиксируются параметрами функции только в том случае, если они объявлены на уровне функций, а не если они объявлены на уровне интерфейса (что имеет смысл).
Как я могу использовать логический вывод s.render<T extends Node[]>(nodes: T)
для ввода функции createNode(name: string, fields: AllTypes<T>)
, где T
- это один и тот же логический тип, общий для двух функций?
Есть ли способ заставить эту работу работать?(даже с немного другим API)
Спасибо ?