获取泛型参数的类型

24
我写了一个小函数来更好地处理类型。
function evaluate(variable: any, type: string): any {
    switch (type)
    {
        case 'string': return String(variable);
        case 'number': return isNumber(variable) ? Number(variable) : -1;
        case 'boolean': {
            if (typeof variable === 'boolean')
                return variable;

            if (typeof variable === 'string')
                return (<string>variable).toLowerCase() === 'true';

            if (typeof variable === 'number')
                return variable !== 0;

            return false;
        }
        default: return null;
    }
}

function isNumber(n: any): boolean {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

我尝试使用泛型,但不知道如何从泛型参数获取类型。这是可能的吗?


不,TypeScript的类型仅是一个编译时特性。输出的JavaScript没有类型信息,也没有反射机制。您必须像在JavaScript中一样依靠老式的“typeof”在代码中使用。 - Stephen Chung
1
记录一下,你可以将布尔类型的处理程序简化为 return !!variable; - Peter Wone
@PeterWone 这会改变行为,目前只有"true"(不区分大小写)才会返回true,但是对于所有非空字符串,!!variable都会返回true。但是如果您想要的话,可以将!!应用于两个非字符串分支。 - Mingwei Samuel
2个回答

43

您无法消除type字符串,但是通过添加重载,您可以使函数在类型方面更加智能和可用:

function evaluate(variable: any, type: 'string'): string;
function evaluate(variable: any, type: 'number'): number;
function evaluate(variable: any, type: 'boolean'): boolean;
function evaluate(variable: any, type: string): unknown {
    ...
    default: throw Error('unknown type');
}

const myBool = evaluate('TRUE', 'boolean'); // myBool: boolean
const myNumber = evaluate('91823', 'number'); // myBool: boolean
evaluate('91823', 'qwejrk' as any); // RUNTIME ERROR (violated types)

const mysteryType = 'number' as 'boolean' | 'number';
const myMystery = evaluate('91823', mysteryType); // COMPILER ERROR, no overload matches.

游乐场链接

请注意,现在没有空值情况了,因为在编译时不可能知道未知的string类型是否实际包含一个有效值,如'number'

对于大多数人来说,这已经足够好了。


然而...

请注意上面的mysteryType联合类型无法工作。如果你真的非常非常想让它工作,可以使用条件类型代替:

function evaluate<T extends string>(variable: any, type: T):
    T extends 'string' ? string :
    T extends 'number' ? number :
    T extends 'boolean' ? boolean :
    never;
function evaluate(variable: any, type: string): unknown {
    ...
    default: throw Error('unknown type');
}

const mysteryType = 'number' as 'boolean' | 'number';
const myMystery = evaluate('91823', mysteryType); // myMystery: number | boolean

游乐场链接


此外,如果你在谷歌上搜索这个问题并想知道如何从MyClass<T>获取T,那也是可能的:

class MyClass<T> {}

type GetMyClassT<C extends MyClass<any>> = C extends MyClass<infer T> ? T : unknown;

const myInstance = new MyClass<"hello">();
let x: GetMyClassT<typeof myInstance>; // x: "hello"

游乐场链接


12
此外,如果您在谷歌上搜索了这个问题,并且想知道如何从MyClass<T>中获取T,那也是可能的。这就是我在这里的原因,谢谢! - zaphod1984

23

typeof 是 JavaScript 的一个运算符。它可以在运行时获取 JavaScript 知道的类型。泛型是 TypeScript 的概念,它有助于检查代码的正确性,但不会存在编译输出中。因此,简短的答案是不可能的。

但是你可以尝试像这样做:

class Holder<T> {
    value: T;
    constructor(value: T) {
        this.value = value;
    }
    typeof(): string {
        return typeof this.value;       
    }
}

这是因为我操作的是 Holder 内部的值,而不是 Holder 本身。

试一下


1
返回this.value.constructor['name']; // <- 在typescript playground上似乎可行。来自这里。可能会有缩小等问题。 - John Stephenson
理论上你也可以这样做: function create<T>(c: {new(): T; }): T { return new c(); }我无法让它工作 来自 https://www.typescriptlang.org/docs/handbook/generics.html - titusfx
4
如果我传递自己的对象,比如汽车,它会弹出"object"而不是"Car"。 - mumair
1
"typeof" 是 JavaScript 运算符。在类型上下文中,typeof 也是 TypeScript 运算符,它可以给出其操作数的 TypeScript 类型。我不知道它是否存在于2013年,当这个答案最初被写出来时。 :-) - T.J. Crowder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接