簡體   English   中英

從類型的默認參數進行 TypeScript 類型推斷

[英]TypeScript type inference from default parameter of type

給出以下示例:

interface Foo {
  name: string;
}

interface Bar extends Foo {
  displayName: string;
}

const foo: Foo = { name: "foo" };
const bar: Bar = { name: "bar", displayName: "dn" };

const getName = <T extends Foo>(obj: T = foo): string => {
  return obj.name;
};

getName(foo); // Ok
getName(bar); // Ok

obj: T = foo導致錯誤。 即使T extends Foo ,這也不被接受。 為什么會這樣,有什么解決方法?

例子

您的getName函數不需要泛型,並且可以對輸入參數obj使用Foo類型注釋,即:

const getName = (obj: Foo = foo): string => {
  return obj.name;
};

盡管您將類型Foo分配給obj它也適用於getName(bar); 因為Bar extends Foo 換句話說:由於 TypeScript 知道FooBar更具體,因此getName函數將接受Bar類型的任何元素。

您不需要泛型,因為您不想將函數的不同部分相互關聯。 如果您想將輸入參數與輸出參數相關聯,則可以有效使用泛型。

請參閱您的代碼的此TS Playground

另請參閱有關您遇到的錯誤的相關問題,即

Type 'Foo' is not assignable to type 'T'.
  'Foo' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Foo'.(2322)

問題是foo不是T類型,假設您想使用接口Bar實例化泛型:

const getName = (obj: Bar = foo): string => {
  return obj.name;
};

您可以看到foo不是Bar (缺少displayName屬性)並且您不能將其分配給Bar類型的變量。

您現在有三個選擇:

  1. 強制foo用作泛型T : <T extends Foo>(obj: T = foo as T): string => ... 但這是您能做的最糟糕的選擇(可能導致意外結果/錯誤)。

  2. 重載您的函數以匹配您的通用規范。 如果您需要返回(並實際使用)您的通用實例,這很有用:

const getName: {
  // when you specify a generic on the function
  // you will use this overload
  <T extends Foo>(obj: T): T;

  // when you omit the generic this will be the overload
  // chosen by the compiler (with an optional parameter)
  (obj?: Foo): Foo;
}
= (obj: Foo = foo): string => ...;
  1. 請注意,您的函數根本不使用泛型並將參數作為簡單的Foo : (obj: Foo = foo): string => ...傳遞。 在您的情況下,這應該是最好的

暫無
暫無

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

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