簡體   English   中英

如何寫一個抽象的 typescript 泛型類型?

[英]How to write an abstract typescript generic type?

給定以下類型

interface Base {
  id: string;
}

interface A extends Base {
  propA: string;
}

interface B extends Base {
 propB: string;
}

我想表達一個具有以下約束的通用MyGeneric<T>

  1. T必須是 object
  2. T鍵必須是string
  3. T值必須是instanceOf Base (類型為Base或擴展 Base 的類型)

    (3. T值是否必須與Base接口兼容,但已重新措辭以避免誤解)

我試過了

interface MyConstraint {
  [key: string]: Base
}

interface MyGeneric<T extends MyConstraint> {
  data: T
}

但是在這種情況下,當用戶想要使用它時,它有兩個缺點:

interface userDefinedInterface1 {
  a: A;
  b: B;
}

function foo1(p: MyGeneric<userDefinedInterface1>):void {
  //drawback 1: this throws TS2344:
  //Type 'userDefinedInterface1' does not satisfy the constraint 'userDefinedInterface1'.   //Index signature is missing in type 'userDefinedInterface1'.
}

//to solve drawback 1, the user has to extend MyConstraint
interface userDefinedInterface2 extends MyConstraint {
  a: A;
  b: B;
}

function foo2(p: MyGeneric<userDefinedInterface2>):void {
  //drawback 2: here, ts considers every string property as valid because of [key: string] 
  console.log(p.data.arbitraryKey);//this is valid
}

有沒有辦法定義interface MyGeneric<T>以尊重提到的 3 個約束而沒有這兩個缺點?

只有一個限制——如果你想添加額外的密鑰,你必須指定它們。

interface Base {
  id: string;
  num: number;
}

interface A extends Base {
  propA: string;
}

interface B extends Base {
 propB: string;
}

type MyGeneric<T extends Base, K extends keyof any = never> = {
  data: T & {
    [key in K | keyof T]: key extends keyof T ? T[key] : string;
  }
}


const test1: MyGeneric<B, 'test'> = {
  data: {
    id: '123',
    num: 123,
    propB: '123',
    test: '123',
  },
};
const test2: MyGeneric<B> = {
  data: {
    id: '123',
    num: 123,
    propB: '123',
    test: '123', // fails, it has to be provided in current TS.
  },
};

操場

如果您只想依賴T的鍵。

然后只需使用此版本:

type MyGeneric<T extends Base> = {
  data: T & {
    [key in keyof T]: key extends keyof Base ? Base[key] : string;
  }
}

我認為這應該可以解決您的兩個缺點:

type MyConstraint<T> = {
  [K in keyof T]: T[K] extends Base ? T[K] : never;
};

interface MyGeneric<T extends MyConstraint<T>> {
  data: T;
}

以低廉的價格使MyConstraint通用。 如果你做了類似的事情,你的兩個例子現在應該可以工作了,當然還有:

interface UserDefinedInterface3 {
  a: A;
  b: B;
  c: string;
}

type Wrong = MyGeneric<UserDefinedInterface3>;

您會收到一條錯誤消息,指出屬性c的類型不兼容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM