簡體   English   中英

通用 Typescript function 是否可以有多種返回類型?

[英]Is it possible to have multiple return types for a generic Typescript function?

我目前正在設計一個帶有 Typescript 的 web 服務器並且遇到了死胡同。 目標是有一個接口或類似的東西,讓任何其他沒有深入了解系統 rest 的開發人員進來,實現他們自己的解析器版本,並讓它與系統的 rest 一起工作。 此外,我希望可以選擇在不修改原始代碼的情況下添加更多返回類型。

目前,我已經定義了數據的形狀,並且我正試圖將我的頭繞在解析器本身上。 數據如下所示:

export namespace CardData {
   export interface Base {
        type: string;
        source: Source;
    }

    export interface Graph {
        labels: string[];
        data: number[];
    }

    // Other definitions below
}

解析器界面如下所示:

export interface Source {
    id: number;
    name: string;
    url: string;
    isReachable: boolean;
    type: string;
}

export interface ConnectorArgument {
    id: number;
    key: string;
    value: string;
}

export interface Parser {
    // Unrelated code

    // The type of T depends on args
    getSource: <T>(
        source: Source,
        args: ConnectorArgument[]
    ) => Promise<T>;
}

但是如果我實現 getSource 並嘗試返回任何東西,我會得到:

'T' could be instantiated with an arbitrary type which could be unrelated to 'Graph'.

我理解為什么 Typescript 拒絕讓這個工作,因為 T 的類型是由 function 的調用者確定的,但我還沒有想出一個好的替代方案。

我已經查看了其他問題,例如此處此處,但沒有一個真正適合我的問題。 這甚至可以在 Typescript 中做到,還是我最好使用其他語言?

編輯 1:我添加了 Source 和 ConnectorArgument 的定義。

由於source arg 中的字符串type屬性應確定整體返回類型,因此有一個 TypeScript 范例可以處理此映射。 如果您想查閱更廣泛的示例,它與 typeScript 的 DOM 聲明中的addEventListener及其親屬使用的相同。

在您的情況下,您需要在type字符串值和將為它們返回的實際類型之間創建一個 map 接口。 getSource的返回類型將是從該 map 中查找的內容。 不幸的是,由於此處描述的 TypeScript 中的一些限制,在返回每種可能的類型時需要進行不雅的轉換。 以下是它的外觀(以更簡單的結構為例):

interface Widget { foo: number }
interface Sprocket { bar: number }

interface SourceTypeMap {
    'widget': Widget;
    'sprocket': Sprocket;
}

interface Source {
    type: keyof SourceTypeMap;
}

interface Parser {
    getSource: <T extends keyof SourceTypeMap>(
        source: Source & { type: T }
    ) => Promise<SourceTypeMap[T]>;
}

class ExampleParser implements Parser {
    async getSource<T extends keyof SourceTypeMap>(
        source: Source & { type: T }
    ): Promise<SourceTypeMap[T]> {
        return ((): SourceTypeMap[keyof SourceTypeMap] =>
        {
            switch (source.type) {
            case 'widget':
                return { foo: 42 };
            case 'sprocket':
                return { bar: 42 };
            }
            throw new TypeError(`unsupported type '${source.type}'`);
        }) () as SourceTypeMap[T];
    }
}

async function test() {
    const parser = new ExampleParser ();
    const widget = await parser.getSource({ type: 'widget' }); // infers Widget type
    console.log(widget); // { foo: 42 }
    const sprocket = await parser.getSource({ type: 'sprocket' }); // infers Sprocket type
    console.log(sprocket); // { bar: 42 }
}

test();

這是 TypeScript Playground 上的可運行版本。

暫無
暫無

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

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