【问题标题】:complex generic type constraint and type inferrance复杂的泛型类型约束和类型推断
【发布时间】:2021-06-23 23:45:41
【问题描述】:

我正在尝试在 TypeScript 中构建一个微型 ORM,但我遇到了这个编译问题:

Type 'TObject' does not satisfy the constraint '{ [k in k]: object; }'.
  Type 'object' is not assignable to type '{ [k in k]: object; }'.

有人知道为什么这个代码示例会引发编译错误吗?以及如何解决?

type NavigationProperties<T, TKey extends keyof T> = T[TKey] extends object ? TKey : never;
 type Relationship<T extends { [k in TMember]: TTarget }, TMember extends keyof T, TTarget extends object = object> = {
    name: TMember,
    isComposite?: boolean,
};
class A<TObject extends object>
{
    public readonly relationships: Partial<{ [k in NavigationProperties<TObject, keyof TObject>]: Relationship<TObject, k> }> = { }
}

Playground

编辑

根据 Shivam 的要求,我正在为其添加更多上下文:当我有混合类型或不匹配的类型时,我也想让它工作: Playground

【问题讨论】:

  • 也发布错误信息
  • NavigationProperties 解析为 never 如果 T 的任何键不扩展 object。是故意的吗?
  • 是的,如果我的类型不包含任何关系/导航属性,这是故意的。

标签: typescript typescript-generics mapped-types


【解决方案1】:

问题

Relationship 类型中,T 被限制为{ [k in TMember]: TTarget },而声明属性relationshipsTObject 被传递,其类型为object,它是{ [k in TMember]: TTarget } 的超类型。因此不兼容。

解决方案

type NavigationProperties<T, TKey extends keyof T> = T[TKey] extends object ? TKey : never;

type TObject<T extends object, TType extends object> = { [K in keyof T]: TType }

type Relationship<T extends TObject<T, TType>, TKeys extends keyof T, TType extends object> = {
    name: TKeys,
    isComposite?: boolean,
};

type Relationships<T extends TObject<T, TType>, TType extends object> = {
    [K in NavigationProperties<T, keyof T>]?: Relationship<T, K, TType>
}

class A<T extends TObject<T, TType>, TType extends object = object> {
    public readonly relationships: Relationships<T, TType> = { }
}

// example usage
type MyType = {
    prop1: number
    porp2: string
}

type X = {
    a: MyType
    b: MyType
}

declare const obj: A<X>

obj.relationships // type is Relationships<X, object>

// type of obj1.relationships.a is Relationship<X, "a", object>
obj.relationships.a?.name // "a"
obj.relationships.b?.name // "b"

declare const obj1: A<X, MyType>

obj1.relationships // type is Relationships<X, MyType>

// type of obj1.relationships.a is Relationship<X, "a", MyType>
obj1.relationships.a?.name // "a"
obj1.relationships.b?.name // "b"

Playground

【讨论】:

  • 这几乎是完美的。但是,如果类型没有任何关系,或者 X 是关系和非关系的混合,它会中断。这就是我试图通过 never 选项实现的目标。
  • @NicolasPenin 请写一个相同的例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多