簡體   English   中英

Typescript:類型不可分配給條件類型

[英]Typescript: Type is not assignable to conditional type

我有一個 function 查詢我的數據庫,並且根據我們是在提取“已保存”數據還是“未保存”數據將更改 output。 我想把它濃縮成一個 function ,所以我正在使用條件類型讓 Typescript 知道 ZC1C425268E68385D1AB5074C17A94F1 的響應將基於類型改變。

如果保存,function 應該返回一個 ProductType 數組(我制作的一個自定義類型),否則它應該返回一個字符串數組。

type ProductType = {
    title: string;
    price: number;
};

type QueryResponse<T> = T extends 'unsaved'
    ? ProductType[]
    : T extends 'saved'
    ? string[]
    : never;

export async function queryDb<T extends 'saved' | 'unsaved'>(
    type: T,
): Promise<QueryResponse<T>> {
    // Get correct DB URL based on type input.
    let dbUrl: string;
    if (type === 'saved') {
        dbUrl = 'DATABASEURL/saved';
    } else {
        dbUrl = 'DATABASEURL/unsaved';
    }

    // Fetch data from the database.
    const r = await fetch(dbUrl);
    const dbResult = JSON.parse(await r.json());

    // Structure the data correctly to be in line with the types, then return.
    if (type === 'saved') {
        let response: string[] = dbResult.data;
        return response;
    } else {
        let response: ProductExample[] = dbResult.data;
        return response;
    }
}

我在兩個返回語句下都收到錯誤消息: Type 'ProductType[]' is not assignable to type 'QueryResponse<T>'. ,並且Type 'string[]' is not assignable to type 'QueryResponse<T>'. 分別。

不幸的是,雖然您的條件類型QueryResponse<T>正確地從T推斷返回類型,但 TypeScript 無法利用您的type === 'saved'條件作為類型保護:

    // Structure the data correctly to be in line with the types, then return.
    if (type === 'saved') {
        let response: string[] = dbResult.data;
        type // type is NOT narrowed down to "saved" type
        //^? (parameter) type: T extends "saved" | "unsaved"
        return response; // Error: Type 'string[]' is not assignable to type 'QueryResponse<T>'.
    } else {
        let response: ProductType[] = dbResult.data;
        type
        //^? (parameter) type: T extends "saved" | "unsaved"
        return response; // Error: Type 'ProductType[]' is not assignable to type 'QueryResponse<T>'.
    }

正如 smac89 在問題評論中所建議的那樣,您可以跳過嘗試鍵入返回的塊,因為它已經由您的顯式返回類型指定:

export async function queryDb0<T extends 'saved' | 'unsaved'>(
    type: T,
): Promise<QueryResponse<T>> {
    // Etc

    // We may even skip typing the return here, it is already done in the explicit return type
    return dbResult.data;
}

在您的情況下,您甚至可以通過簡單地使用function 重載來避免條件類型:

export async function queryDb2(type: 'saved'): Promise<string[]>
export async function queryDb2(type: 'unsaved'): Promise<ProductType[]>
export async function queryDb2(type: 'saved' | 'unsaved'): Promise<string[] | ProductType[]> {
    // Etc.

    // We may even skip typing the return here, it is already done in the overloads
    return dbResult.data;
}

讓我們檢查一下它的用法:

const s = queryDb2('saved');
//    ^? const s: Promise<string[]>

const u = queryDb2('unsaved');
//    ^? const u: Promise<ProductType[]>

const o2 = queryDb2('other'); // Error: No overload matches this call. Overload 1 of 2, [...] Argument of type '"other"' is not assignable to parameter of type '"saved"'. Overload 2 of 2, [...] Argument of type '"other"' is not assignable to parameter of type '"unsaved"'.

看起來不錯!

游樂場鏈接

暫無
暫無

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

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