简体   繁体   English

Typescript - 如何使用泛型定义返回对象的可索引属性的函数?

[英]Typescript - How to use generics to define a function that returns indexable properties of an object?

I am having trouble writing the correct types for a simple function.我无法为简单函数编写正确的类型。

I want to create a function that when given a key ( keyof any ) or callback will return another function.我想创建一个函数,当给定一个键( keyof any )或回调时将返回另一个函数。 This function takes in some data and returns another key.此函数接收一些数据并返回另一个键。

In other words both toKey('propertyName') and toKey(value => value.propertyName) would return the function value => value.propertyName .换句话说, toKey('propertyName')toKey(value => value.propertyName)都会返回函数value => value.propertyName When called, the function would return the given value of said property only if the value is a string , number or symbol type.调用时,该函数将仅在值为stringnumbersymbol类型时返回所述属性的给定值。

Here's an example:下面是一个例子:

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;

I've attempted to use generics and overloads to achieve the correct typing but it gets complicated very quickly.我尝试使用泛型和重载来实现正确的输入,但很快就会变得复杂。

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];
}

Is there any simpler way to write this?有没有更简单的方法来写这个?

If you want to be explicit in your types, the built-in PropertyKey type can be used:如果你想在你的类型中显式,可以使用内置的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)) {...}

Test it:测试一下:

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 代码示例

You have to use this,你必须使用这个,

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 例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM