簡體   English   中英

Typescript 可選屬性類型通用

[英]Typescript optional property type generic

我希望我的 function 能夠獲取任何類型的對象,但如果對象具有屬性“id”,請確保它是字符串或數字。

這是最小的示例:

interface FnItem {
  id?: string | number;
};

function fn<T extends FnItem>(item: T, callback: (item: T) => void) {
  console.log(item.id);
  callback(item)
};

fn({ name: 'Michel' }, item => item.name);
fn({ name: 'Michel', id: 12 }, item => item.name);

它拋出這個錯誤

Argument of type '{ name: string; }' is not assignable to parameter of type 'FnItem'.
  Object literal may only specify known properties, and 'name' does not exist in type 'FnItem'
---
Property 'name' does not exist on type 'FnItem

錯誤告訴你所有你需要的。 您的FnItem類型上不存在name 如果要添加任意鍵,可以通過添加屬性或添加索引簽名來修復它,如下所示:

interface FnItem {
  id?: string | number;
  [key: string]: any; // or whatever types you accept
};

至於泛型,我現在不知道你需要什么,因為你可以簡單地將 function 定義為

function fn(item: FnItem): void

假設FnItem可能是任何具有任何屬性的 object 或任何 object 其中idnumber|string我寧願堅持這個解決方案:

type FnItem = Record<string, unknown>

type IdValidation<Obj extends Record<string, unknown>> =
    Obj extends { id: infer Id } ? Id extends string | number ? Obj : Obj & { id: never } : Obj;

function fn<T extends FnItem,>(item: IdValidation<T>, callback: (item: IdValidation<T>) => void) {
    console.log(item.id);
    callback(item)
};

fn({ name: 'Michel' }, item => item.name);
fn({ name: 'Michel', id: 12 }, item => item.id);

fn({ name: 'Michel' }, item => item.ya); // error
fn({ name: 'Michel', id: [] }, item => item.id); // id is highlighted as a wrong property

操場

由於第一個參數可能是任何 object,我們應該允許傳遞Record<string,unknown>從而禁用我們關於idnumber|string的約束。 這就是我添加IdValidation實用程序類型的原因。 它只是檢查id屬性是否滿足條件。 如果滿足 - 保持id ,否則 - 將id類型替換為never 使用never允許您僅突出顯示不正確的屬性,這使其易於閱讀和理解。

如果您對 TS 驗證技術感興趣,可以在此處此處查看我的文章

如果你想傳遞一個泛型,那么你需要告訴 function 什么具體類型實現了你的接口:

interface FnItem {
  id?: string | number;
};

function fn<T extends FnItem>(item: T,  callback: (item: T) => void) {
  console.log(item.id);
  callback(item);
};

fn<myType>({ name: 'Michel', id: 12 }, (item:myType)  => { console.log(item.name); });
fn<myType>({ name: 'Michel' }, (item:myType) => { console.log(item.name); });

class myType implements FnItem
{
    name: string = "";
    id?: number;
}

編譯示例

暫無
暫無

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

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