Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/laravel/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 如何根据记录键的值筛选记录键?_Typescript_Generics_Types_Generic Programming_Typescript Generics - Fatal编程技术网

Typescript 如何根据记录键的值筛选记录键?

Typescript 如何根据记录键的值筛选记录键?,typescript,generics,types,generic-programming,typescript-generics,Typescript,Generics,Types,Generic Programming,Typescript Generics,我有这样的记录: interface TheRecord extends TheRecordType { a: { typeA: 'string' }, b: { typeB: 123 }, c: { typeA: 'string' }, } type TheRecordType = Record<string, TypeA | TypeB> type TypeA = { typeA: string } type TypeB = { typeB: number }

我有这样的记录:

interface TheRecord extends TheRecordType {
  a: { typeA: 'string' },
  b: { typeB: 123 },
  c: { typeA: 'string' },
}

type TheRecordType = Record<string, TypeA | TypeB>

type TypeA = { typeA: string }
type TypeB = { typeB: number }
下面是我如何尝试过滤掉它们

type FilteredForTypeA = { [k in keyof TheRecord]: TheRecord[k] extends TypeA ? TheRecord[k] : never }

这里发生了一些事情,所以我将给出一个答案,因为它不是我发现的相关现有问题的直接副本

当您的类型具有索引签名时,如果对象的“已知”文本键是索引签名的子类型,则很难仅提取它们。也就是说,
keyof{[k:string]:any,foo:any}
只是
string
,而
“foo”
完全包含在其中。您可以使用条件类型技巧仅提取已知的文本键,如所示:

类型KnownKeys=提取;
另一方面,您只需要其值具有与特定类型匹配的属性的键。这在映射条件查找中是可行的,如所示:

type KeysMatching={[K in keyof T]:T[K]扩展V?K:never}[keyof T];
把这些放在一起,你会得到:

type KnownKeysMatching<T, V> = KeysMatching<Pick<T, KnownKeys<T>>, V>
类型knownkeymatching=KeysMatching
您可以验证它是否按照我认为您的意图工作:

function doStuff(arg: KnownKeysMatching<TheRecord, TypeA>): void {
}

doStuff('a'); // okay
doStuff('b'); // error!
doStuff('c'); // okay
doStuff('d'); // error! 
函数doStuff(arg:knownkeymatching):无效{
}
多斯塔夫('a');//可以
doStuff('b');//错误!
doStuff('c');//可以
doStuff('d');//错误!
请注意,根据需要,
arg
不能是
'b'
,但也不能是
'd'
或任何其他“未知”字符串,即使
记录
具有字符串索引签名。如果您需要
'd'
的其他行为,这是可以做到的,但这似乎超出了问题的范围

希望有帮助;祝你好运


使用稍微修改过的
KnownKeys
版本来排除值也从不扩展的键,您最终会得到以下结果

interface TheRecord extends TheRecordType {
  a: { typeA: 'string' },
  b: { typeB: 123 },
  c: { typeA: 'string' },
}

type TheRecordType = Record<string, TypeA | TypeB>
type KnownKeys<T> = {
  [K in keyof T]: string extends K ? never : number extends K ? never : T[K] extends never ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;

type TypeA = { typeA: string }
type TypeB = { typeB: number }

function doStuff(arg: KnownKeys<FilteredForTypeA>): void {

}

type FilteredForTypeA = { [k in keyof TheRecord]: TheRecord[k] extends TypeA ? TheRecord[k] : never }

doStuff('b'); // error!
接口记录扩展了记录类型{
a:{typeA:'string'},
b:{typeB:123},
c:{typeA:'string'},
}
类型记录类型=记录
类型KnownKeys={
[K in keyof T]:字符串扩展K?从不:数字扩展K?从不:T[K]扩展从不?从不:K
}扩展{[U]in keyof T]:推断U}?U:从来没有;
类型TypeA={TypeA:string}
类型TypeB={TypeB:number}
函数doStuff(arg:KnownKeys):void{
}
type FilteredForTypeA={[k in key of TheRecord]:TheRecord[k]扩展TypeA?TheRecord[k]:never}
doStuff('b');//错误!

可能是ugh的副本,除非您在其中有索引签名。您可能需要先使用
KnownKeys
,就像在Thanx@jcalz中一样!莱姆文摘。。
type KnownKeysMatching<T, V> = KeysMatching<Pick<T, KnownKeys<T>>, V>
function doStuff(arg: KnownKeysMatching<TheRecord, TypeA>): void {
}

doStuff('a'); // okay
doStuff('b'); // error!
doStuff('c'); // okay
doStuff('d'); // error! 
interface TheRecord extends TheRecordType {
  a: { typeA: 'string' },
  b: { typeB: 123 },
  c: { typeA: 'string' },
}

type TheRecordType = Record<string, TypeA | TypeB>
type KnownKeys<T> = {
  [K in keyof T]: string extends K ? never : number extends K ? never : T[K] extends never ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;

type TypeA = { typeA: string }
type TypeB = { typeB: number }

function doStuff(arg: KnownKeys<FilteredForTypeA>): void {

}

type FilteredForTypeA = { [k in keyof TheRecord]: TheRecord[k] extends TypeA ? TheRecord[k] : never }

doStuff('b'); // error!