Typescript如何推断文字类型或字符串

时间:2020-09-03 10:58:22

标签: typescript typescript-typings typescript-generics

所以我试图根据传入的参数来获取对象。 我发现了这个问题,它与我之后的问题非常接近。 TypeScript function return type based on input parameter 但是,我希望该函数也能够接受字符串,并且当传入的参数不是文字类型时,它将推断any or unknown

让我在代码中表达我的意思。

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}

type TypeName = "circle" | "square" | string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

请注意,TypeName具有文字类型和字符串的并集类型。 我希望看到的是,当我使用类型时,我能够根据参数推断出返回类型。例如:

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: unknown

以上都很好。但是,我无法让IDE建议这些选项。 我希望看到以下选项:'circle' | 'square' | string

那有可能吗?

2 个答案:

答案 0 :(得分:0)

不,这是不可能的,因为string是字符串文字的超级类型,所以

type TypeName = "circle" | "square" | string; 

没什么不同
type TypeName = string; 

但是,您可以使用函数重载来实现目标

type TypeName = "circle" | "square"
type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    never

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]
function getItems(type: string) : unknown[]
function getItems(type: string) {
  // implementation comes here
}

答案 1 :(得分:0)

您可以使用重载和一些条件实用程序类型来做到这一点:

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}


type KnownObject = Circle | Square
type IsKnownTypeName<T extends string, U = KnownObject> = U extends { type: T } ? T : never
type ObjectForType<T extends string, U = KnownObject> = U extends { type: T } ? U : never

function getItems<T extends string>(type: IsKnownTypeName<T>) : ObjectForType<T>[]
function getItems<T extends string>(type: T) : any[]
function getItems<T extends string>(type: T) : any[] {
    return []
}

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: any