簡體   English   中英

Typescript Generics:類型參數推斷與通用默認類型參數

[英]Typescript Generics: Type argument inference vs Generic default type parameter

我正在努力找出Generic default type parameter的正確用例。

下面我創建了一個示例,我希望我的泛型 function 使用泛型默認類型參數而不是類型參數推斷。 但是,它似乎不起作用。 我想我無法區分typescript generics這兩個概念。

interface Person<K extends string | number | symbol = string> {
  addPerson: (key: K) => void;
}

interface StandardObject {
    [key: string]: string;
}

// sometimes I want keys to be string and sometimes string literal
declare function returnPerson<T extends StandardObject = StandardObject>(param: T): Person<keyof T>;

var obj = {
  name: "subrato",
  gender: "male"
}

const record = returnPerson(obj) 
record.addPerson('nam'); // I don't need this error, I want to ignore it 
// above line should not throw error but bcz of type argument inference it doesn't
// Why TS uses type argument inference here, why not generic default type parameter `StandardObject`?

const record2 =  returnPerson<StandardObject>(obj);
// here TS doesn't yell 
// since we explicit define object type argument whose key's would be string
// I don't want to be explicit to ignore the string literal type
record2.addPerson("nam");

const record3 = returnPerson<typeof obj>(obj);
// I want obj key should accept string literal constant only If I have given the type argument like in this record3 example.
record3.addPerson("nam")

游樂場鏈接

一般問題:當 TS 使用 generics 默認類型參數而不是類型參數推斷時?

我的要求是我的通用 function returnPerson接受 object 其鍵類型有時是字符串,有時是字符串文字。

TL;DR當您使用泛型類型參數作為 function 參數的類型時,類型信息將從該參數的 position 中使用的參數類型推斷出來。


考慮以下示例 - 它與您的問題基本相同,除了它包含您的 function 聲明的實現並且更改了幾個名稱,但是,重要部分是相同的(類型泛型)。

TS游樂場

type PersonAdder<K extends PropertyKey = string> = {
  addPerson: (key: K) => void;
};

type StringObject = Record<string, string>;

function makePersonAdder <T extends StringObject = StringObject>(param: T): PersonAdder<keyof T> {
// Is the same as no default type parameter because inference always takes place:
// function makePersonAdder <T extends StringObject>(param: T): PersonAdder<keyof T> {
  return {
    addPerson (key) {
      console.log(key);
    },
  };
};


// Use:

const obj = {
  name: "subrato",
  gender: "male",
};

const a1 = makePersonAdder(obj); // PersonAdder<"name" | "gender">
a1.addPerson('name'); // ok
a1.addPerson('gender'); // ok
a1.addPerson('nam'); /*
             ~~~~~
Argument of type '"nam"' is not assignable to parameter of type '"name" | "gender"'.(2345) */

const a2 = makePersonAdder<typeof obj>(obj); // PersonAdder<"name" | "gender"> (identical to a1, original keys are inferred)
a2.addPerson('nam');
//           ~~~~~
// same error as with a1


const a3 = makePersonAdder(obj as StringObject); /* PersonAdder<string>
                               ^^^^^^^^^^^^^^^
Use a type assertion so that the inferred keys are simply 'string' */

a3.addPerson('name'); // ok
a3.addPerson('gender'); // ok
a3.addPerson('nam'); // ok
a3.addPerson('any other string'); // ok
a3.addPerson(42); /*
             ~~
Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */

const a4 = makePersonAdder<StringObject>(obj); // PersonAdder<string> (identical to a3)
a4.addPerson('any other string'); // ok
a4.addPerson(42); /*
             ~~
Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */

const a5 = makePersonAdder(obj as any); // PersonAdder<string | number | symbol>
a5.addPerson('any other string'); // ok
a5.addPerson(42); // ok

在 function makePersonAdder中,使用了泛型類型參數T

T既用作可作為參數param ( extends StringObject ) 的參數提供的內容的約束,又用作用於保存為參數param提供的參數的推斷類型的變量。 因為返回類型使用從T ( PersonAdder<keyof T> ) 推斷的類型信息,所以在創建返回類型時,參數值的類型總是用於推斷。

在上面的代碼中,有多個示例用法:

  • a1obj的類型推斷鍵,所以返回類型是PersonAdder<"name" | "gender"> PersonAdder<"name" | "gender">

  • a2是通過為T提供精確類型創建的,因此不會根據提供的參數進行推斷。 相反,您提供的參數必須擴展提供的類型。 在這種情況下,它們是相同的類型,所以就像a1一樣,返回類型是PersonAdder<"name" | "gender"> PersonAdder<"name" | "gender"> (從typeof obj推斷)。

  • a3在提供的參數上使用類型斷言,以便編譯器從斷言類型而不是原始參數的類型推斷。 這導致返回類型為PersonAdder<string>

  • a4a2發生的情況相同,只是這次為T提供的手動類型是StringObject ,因此返回類型推斷出StringObject的鍵(它們是string ),從而產生PersonAdder<string>

  • a5再次使用類型斷言,這次斷言obj是類型any any是一種特殊的頂級類型,您可以將其視為本質上允許任何類型信息。 因為這種類型非常廣泛,沒有什么可以限制推理,所以使用所有允許的類型,導致PersonAdder<string | number | symbol> PersonAdder<string | number | symbol> PersonAdder<string | number | symbol>

暫無
暫無

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

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