![](/img/trans.png)
[英]Mixing union types, generics and conditional types causes unexpected "Type is not assignable to type" error
[英]Typescript generics + conditional types is not assignable to type error
我正在使用條件類型通過類泛型自動推斷數據結構的類型。 出於某種原因,它沒有推斷ObjectType
構造函數中的ObjectType
。
export type NodeType<T> = T extends (infer U)[] ? ArrayNode<U> : ObjectNode<T>
export abstract class Node {}
export class ObjectNode<T> extends Node {
constructor(public fields: { [key in keyof T]: Field<NodeType<T[key]>> }) {
super()
}
public data: T
}
export class ArrayNode<T> extends Node {
public data: T[]
constructor(public ofType: NodeType<T>) {
super()
}
}
class Field<T extends Node> {
constructor(public node: T) {}
}
const User = new ObjectNode({})
const query = new ObjectNode({
user: new Field(User),
// ****************
/// The below `users` field should be automatically be detected as 'Field<ArrayNode<{}>>', but for some reason it's 'Field<ObjectNode<{}>>'.
/// Property 'fields' is missing in type 'ArrayNode<{}>' but required in type 'ObjectNode<{}>'.
// ****************
users: new Field(new ArrayNode(User))
})
var q: ObjectNode<{ users: {}; user: {} }>
q.fields.users.node.fields
q.fields.user.node.fields
q.data.user
q.data.users
query.fields.users.node.fields
query.fields.user.node.fields
query.data.user
query.data.users
我不認為打字稿可以按照條件類型的邏輯來提取T
。 您需要顛倒邏輯,將節點類型作為類型參數,並手動從節點類型中提取數據類型。 解決方案可能如下所示:
export abstract class Node { }
type AllNodeTypes = ArrayNode<any> | ObjectNode<any>
export type NodeDataType<T extends AllNodeTypes> = T['data']; // can be a conoditional type with infer if needed (ie if not all node types have a data field)
export type ObjectNodeDataType<T extends Record<keyof T, Field<AllNodeTypes>>> = {
[P in keyof T]:NodeDataType<T[P]['node']>
}
export class ObjectNode<TNode extends Record<keyof TNode, Field<AllNodeTypes>>> extends Node {
constructor(public fields: TNode) {
super()
}
public data: ObjectNodeDataType<TNode>
}
export class ArrayNode<TNode extends AllNodeTypes> extends Node {
public data: NodeDataType<TNode>[]
constructor(public ofType: TNode) {
super()
}
}
class Field<T extends Node> {
constructor(public node: T) { }
}
const User = new ObjectNode({})
const query = new ObjectNode({
user: new Field(User),
users: new Field(new ArrayNode(User))
})
query.fields.users.node.ofType.fields
query.fields.user.node.fields
query.data.user
query.data.users
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.