【问题标题】:Typescript - How to use generics to define a function that returns indexable properties of an object?Typescript - 如何使用泛型定义返回对象可索引属性的函数?
【发布时间】:2020-01-08 18:42:34
【问题描述】:

我无法为一个简单的函数编写正确的类型。

我想创建一个函数,当给定一个键 (keyof any) 或回调将返回另一个函数。这个函数接受一些数据并返回另一个键。

换句话说,toKey('propertyName')toKey(value => value.propertyName) 都会返回函数value => value.propertyName。当被调用时,只有当该属性的值是stringnumbersymbol 类型时,该函数才会返回给定值。

这是一个例子:

function toKey(keyIdentity) { /* snippet */ }

interface IPerson {
    firstName: string,
    lastName: string,
    age: number,
    emails: string[]
};

const getKey1 = toKey((person: IPerson) => person.emails[0]);
const getKey2 = toKey('firstName');
const getKey3 = toKey('emails');

const person: IPerson = {
    firstName: 'Craig',
    lastName: 'Lipton',
    age: 46,
    emails: [
        '<email-1>',
        '<email-2>'
    ]
};

getKey1(person); // returns "<email-1>";
getKey2(person); // returns "Craig";
getKey3(person); // not allowed;

我尝试使用泛型和重载来实现正确的输入,但它很快就变得复杂了。

function toKey(key?: null): () => void;
function toKey<K extends keyof any>(key: K): <U extends keyof any>(item: Record<K, U>) => U;
function toKey<T extends (...args: any[]) => keyof any>(key: T): T;
function toKey(key: any): any {
    if (isNil(key)) {
        return noop;
    }

    return isFunction(key) ? key : (value: T) => value[key];
}

有没有更简单的方法来写这个?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    如果你想在你的类型中显式,可以使用内置的PropertyKey 类型:

    // type PropertyKey = string | number | symbol
    
    function toKey<K extends PropertyKey>(key: K): 
      <T extends Record<K, PropertyKey>>(t: T) => PropertyKey
    function toKey<T>(fn: (t: T) => PropertyKey): (t: T) => PropertyKey
    function toKey(key: PropertyKey | ((t: Record<PropertyKey, PropertyKey>) => PropertyKey)) {...}
    

    测试一下:

    toKey((person: IPerson) => person.emails[0])(person); // "<email-1>";
    toKey('firstName')(person); // "Craig";
    toKey('emails')(person); // error, emails prop is not string | number | symbol
    toKey('lastName')({ firstName: "Lui" }); // error, object passed in has no key "lastName"
    

    Code sample

    【讨论】:

    • 不错!我不知道PropertyKey!这使事情更具可读性!谢谢。
    【解决方案2】:

    你必须使用这个,

    function toKey<T, K extends keyof T = keyof T>(key: K): (v: T) => T[K];
    
    const getKey3 = toKey<IPerson>('emails');
    const getKey3 = toKey<IPerson,"emails">('emails');
    

    Example

    【讨论】:

    • 感谢您的快速回复!是的,这没关系,但是我需要指定使用它的类型。如果我仍然可以像普通 javascript 一样使用它会很好(即toKey('emails'))。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 2019-08-23
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    相关资源
    最近更新 更多