如何根据 Typescript 中的参数控制返回类型?

Car*_*ven 0 typescript typescript-generics typescript-typings

我有一个工厂类,它将返回不同的类,这些类都实现了相同的接口但具有不同的泛型。但是,我的工厂类无法确定接口使用的不同泛型类型。

例如,我有以下接口:

interface ICityData<T> {
    data: T
}

interface LondonData {
    a: string,
    b: number
}

interface BerlinData {
    c: string,
    d: string
}

interface NewYorkData {
    a: Record<any, any>,
    e: number
}

interface ICityConcrete<T> {
    retrieve(): T
}
Run Code Online (Sandbox Code Playgroud)

我有以下具体类,它们都实现了ICityConcrete接口,但使用了不同的泛型类型:

class LondonConcrete implements ICityConcrete<LondonData> {
    retrieve(): LondonData {
        return {
            a: 'test',
            b: 123
        }
    }
}

class BerlinConcrete implements ICityConcrete<BerlinData> {
    retrieve(): BerlinData {
        return {
            c: 'abc',
            d: 'efg'
        }
    }
}

class NewYorkConcrete implements ICityConcrete<NewYorkData> {
    retrieve(): NewYorkData {
        return {
            a: {
                name: 'test'
            },
            e: 321
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,我有一个工厂来根据city提供的参数来创建这些类:

enum City {
    London,
    NewYork,
    Berlin
}

class MyFactory {
    public static create(city: City): ICityConcrete<TDependsOnCity> {     // TDependsOnCity could be LondonData, BerlinData or NewYorkData depending on the city argument
        switch (city) {
            case City.London:
                return new LondonConcrete();
            case City.Berlin:
                return new BerlinConcrete();
            default:
                return new NewYorkConcrete(); 
        }
    }
}

const myCreatedInstance = MyFactory.create(City.London);
Run Code Online (Sandbox Code Playgroud)

这就是问题所在,我想myCreatedInstance成为ICityConcrete<TDependsOnCity>. 换句话说,类型应该取决于所city提供的。如果City.London在参数中提供,myCreatedInstance则应为 类型ICityConcrete<LondonData>

我试图以不同的方式重新排列事物,ICityConcrete<any>无论我使用什么,它们中的大多数都具有city

在此处输入图片说明

如何根据本例中提供的参数控制返回类型?

TS游乐场

Ale*_* L. 5

您可以定义并使用城市类型来构造映射:

const cityConstructors = {
    [City.London]: LondonConcrete,
    [City.Berlin]: BerlinConcrete,
    [City.NewYork]: NewYorkConcrete,
};

class MyFactory {
    public static create<TCity extends City>(city: TCity): InstanceType<(typeof cityConstructors)[TCity]>
    public static create(city: City) {
        return new cityConstructors[city]();
    }
}

const myCreatedInstance = MyFactory.create(City.London) // LondonConcrete
Run Code Online (Sandbox Code Playgroud)

操场