【问题标题】:Get type of generic parameter获取泛型参数的类型
【发布时间】:2013-08-15 11:18:13
【问题描述】:

我写了一个小函数来更好地处理类型。

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
  • 作为记录,您可以将布尔处理程序折叠到return !!variable;
  • @PeterWone 这会改变行为,目前只有 "true"(不区分大小写)会导致 true,但 !!variable 会导致所有非空字符串为 true。可以申请!!如果您愿意,可以到两个非字符串分支。

标签: generics types typescript


【解决方案1】:

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

但你可以这样做:

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

Try it out.

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

【讨论】:

  • 返回 this.value.constructor['name']; // here。可能是缩小等问题。
  • 理论上你也可以这样做:function create(c: {new(): T; }): T { return new c();我无法从typescriptlang.org/docs/handbook/generics.html得到它的工作
  • 如果我传递我自己的对象,例如 Car,它会提醒“对象”;而不是“汽车”
【解决方案2】:

您无法消除 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.

Playground Link

请注意,不再有 null 情况,因为在编译时无法知道未知的 string 类型是否实际上包含像 'number' 这样的有效值。

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


不过……

请注意上面的神秘类型联合不起作用。如果出于某种原因你真的真的很想让它工作,你可以使用条件类型来代替:

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

Playground Link


此外,如果您在 Google 上搜索过这个问题,并且想知道如何从 MyClass&lt;T&gt; 获取 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"

Playground Link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多