类型脚本函数,其中对象的字符串类型属性由另一个参数决定。

问题描述 投票:0回答:1

我想创建一个TypeScript函数,该函数接受一个对象和该对象中的一个属性,其值是一个 string. 使用 <T, K extends keyof T> 的键,以确保只有 T 允许作为属性的值,但我似乎无法缩小范围,使键也必须指向类型为 string. 这可能吗?

我试了一下

function getKey<T extends {K: string}, K extends keyof T>(item: T, keyProperty: K): string {
     return item[keyProperty];
}

但它只是说 Type 'T[K]' is not assignable to type 'string'. 为什么不 T extends {K: string} 约束 T[K] 其实是 string或者说,所提供的 K 必须满足这个条件,这样 T[K] 是一个 string?

为了清楚起见,我希望能够像这样调用这个函数。

getKey({foo: 'VALUE', bar: 42}, 'foo') => return 'VALUE';

getKey({foo: 'VALUE', bar: 42}, 'bar') => should not be allowed since 'bar' is not a string property of the supplied object

getKey({foo: 'VALUE', bar: 'ANOTHER VALUE'}, 'bar') => return 'ANOTHER VALUE'
typescript typescript-generics keyof
1个回答
2
投票

在。{K: string}జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ K 名正言顺 字符串 键。 这就跟你写的是 {"K": string}:

type Oops = { "K": string };
// type Oops = { K: string; }

既然你想 K 拟为 类型 的钥匙,你需要用 映射型,它在一些键的联合上迭代... 要么是 {[P in K]: string}或同等条件 Record<K, string> 使用 Record<K, T> 实用型:

function getKey<T extends { [P in K]: string }, K extends keyof T>(
    item: T,
    keyProperty: K
): string {
    return item[keyProperty]; // no error
}

而你的调用代码的表现(大部分)是你所期望的。

getKey({ foo: 'VALUE', bar: 42 }, 'foo'); // okay
getKey({ foo: 'VALUE', bar: 42 }, 'bar'); // error!
//   ----------------> ~~~
// number is not assignable to string
getKey({ foo: 'VALUE', bar: 'ANOTHER VALUE' }, 'bar'); // okay

我说 "大部分 "是因为你可能希望第二行中的错误是发生在 "我 "身上。'bar' 传入 keyProperty而实际发生的情况是,错误是发生在 bar 的值的属性。item.

只要再多做一点手脚,你就能实现这个目标。

type KeysMatching<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];

function getKey2<T extends { [P in K]: string }, K extends KeysMatching<T, string>>(
    item: T,
    keyProperty: K
): string {
    return item[keyProperty];
}

在这里,我们限制 K 不只是 keyof T但对具体的键 T 其值为 string. 我们用我们自己的 KeysMatching<T, V> 工具类型。 这不会改变什么值最终会是有效的,但它确实改变了编译器在无效时的抱怨。

getKey2({ foo: 'VALUE', bar: 42 }, 'foo'); 
getKey2({ foo: 'VALUE', bar: 42 }, 'bar'); // error!
//  -----------------------------> ~~~~~
//  "bar" is not "foo"
getKey2({ foo: 'VALUE', bar: 'ANOTHER VALUE' }, 'bar');

好的,希望能帮到你,祝你好运!

代码的游戏场链接


1
投票
function getKey<T>(item: T, keyProperty: {[K in keyof T]: T[K] extends string ? K : never}[keyof T]): string {
    return <string> <unknown> item[keyProperty];
}

有点笨重,但我......它的工作原理:)

© www.soinside.com 2019 - 2024. All rights reserved.