Typescript 按名称以字符串形式返回对应的输入类型(字符串模板文本) type generatarrayKeyType=`${T}.${K}`; 类型PathImpl= 键扩展字符串 ? T[Key]扩展只读未知[]? GeneratorArrayKeyType :T[键]扩展记录 ? | `${Key}.${PathImpl&string}` |`${Key}.${Exclude&string}` :从不 :从不; PathImpl2型=PathImpl | keyof T; type Path=PathImpl2扩展字符串| keyof T?路径2:keyof T; 类型路径值= P扩展了`${inferkey}.${inferrest}` ? 键扩展了keyt的键 ? Rest扩展路径 ? 路径值 :T[Key]扩展(推断U)[] ? U :从不 :从不 :P扩展了T的键 ? T[P] :从不; 类型DeepNest={ 测试:字符串[], } 类型数据={ 数组:字符串[], 测试:字符串, 最后:弦,, 文件:文件[], 日期:日期[], 嵌套:{ 测试:字符串, }, 深度:{ 数组:DeepNest[] } } 类型paths=路径; 功能测试(名称:B):路径值{ 将“”返回为任意值; } 常量输出=测试(“测试”)
我想从字符串中提取类型。上面的代码与名称查找Typescript 按名称以字符串形式返回对应的输入类型(字符串模板文本) type generatarrayKeyType=`${T}.${K}`; 类型PathImpl= 键扩展字符串 ? T[Key]扩展只读未知[]? GeneratorArrayKeyType :T[键]扩展记录 ? | `${Key}.${PathImpl&string}` |`${Key}.${Exclude&string}` :从不 :从不; PathImpl2型=PathImpl | keyof T; type Path=PathImpl2扩展字符串| keyof T?路径2:keyof T; 类型路径值= P扩展了`${inferkey}.${inferrest}` ? 键扩展了keyt的键 ? Rest扩展路径 ? 路径值 :T[Key]扩展(推断U)[] ? U :从不 :从不 :P扩展了T的键 ? T[P] :从不; 类型DeepNest={ 测试:字符串[], } 类型数据={ 数组:字符串[], 测试:字符串, 最后:弦,, 文件:文件[], 日期:日期[], 嵌套:{ 测试:字符串, }, 深度:{ 数组:DeepNest[] } } 类型paths=路径; 功能测试(名称:B):路径值{ 将“”返回为任意值; } 常量输出=测试(“测试”),typescript,Typescript,我想从字符串中提取类型。上面的代码与名称查找test一起工作,但是,返回类型将返回所有类型,而不是目标输入类型。欢迎提出任何建议和想法 如果我理解正确,您的问题与递归模板文字类型别名的行为几乎没有关系,因此为了生成一个最小的可复制示例,让我们抛开所有这些定义,只需检查以下函数并尝试调用它: type GenerateArrayKeyType<T extends string, K extends number> = `${T}.${K}`; type PathImpl<T,
test
一起工作,但是,返回类型将返回所有类型,而不是目标输入类型。欢迎提出任何建议和想法
如果我理解正确,您的问题与递归模板文字类型别名的行为几乎没有关系,因此为了生成一个最小的可复制示例,让我们抛开所有这些定义,只需检查以下函数并尝试调用它:
type GenerateArrayKeyType<T extends string, K extends number> = `${T}.${K}`;
type PathImpl<T, Key extends keyof T> =
Key extends string
? T[Key] extends readonly unknown[] ?
GenerateArrayKeyType<Key, 0 | 1>
: T[Key] extends Record<string, any>
? | `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof any[]>> & string}`
| `${Key}.${Exclude<keyof T[Key], keyof any[]> & string}`
: never
: never;
type PathImpl2<T> = PathImpl<T, keyof T> | keyof T;
type Path<T> = PathImpl2<T> extends string | keyof T ? PathImpl2<T> : keyof T;
type PathValue<T, P extends Path<T>> =
P extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: T[Key] extends (infer U)[]
? U
: never
: never
: P extends keyof T
? T[P]
: never;
type DeepNest = {
test: string[],
}
type Data = {
array: string[],
test: string,
last: string,
file: File[],
date: Date[],
nest: {
test: string,
},
deep: {
array: DeepNest[]
}
}
type Pathes = Path<Data>;
function test<T, B extends Path<T> = Path<T>>(name: B): PathValue<T, B> {
return '' as any;
}
const output = test<Data>('test')
当然,这是失败的,因为没有任何东西可以推断T
。另一方面,如果使用尖括号调用函数,编译器将不会为您推断任何类型参数:
它可以工作,但有一个缺点,就是您给函数指定了一个类型为T
的值,它在运行时实际上并不需要这个值
或者,您可以使用带有单个类型参数的泛型函数手动指定,这将返回带有另一个类型参数的泛型函数以推断:
declare function minTestDummy<T, K extends keyof T>(dummyT: T, k: K): T[K];
minTestDummy(null! as Data, "test").toUpperCase(); // okay
声明函数minTestCurry():(k:k)=>T[k];
minTestCurry()(“测试”).toUpperCase();//可以
const dataTest=minTestCurry();
dataTest(“test”).toUpperCase();//可以
这也可以工作,但有一个缺点,就是您在运行时调用了一个额外的函数。就我个人而言,我更喜欢咖喱,因为它将手工部分与推理部分分开,但任何一种方法都应该有效
将当前解决方案转换回问题中的代码如下所示:
declare function minTestCurry<T>(): <K extends keyof T>(k: K) => T[K];
minTestCurry<Data>()("test").toUpperCase(); // okay
const dataTest = minTestCurry<Data>();
dataTest("test").toUpperCase(); // okay
declare function test():(名称:B)=>PathValue;
常量输出=test()('test')
非常感谢您!这个答案是如此全面和详细。
minTest<Data, "test">("test"); // minTest<Data, "test">()
minTest<Data>("test") // minTest<Data, keyof Data>()
declare function minTestDummy<T, K extends keyof T>(dummyT: T, k: K): T[K];
minTestDummy(null! as Data, "test").toUpperCase(); // okay
declare function minTestCurry<T>(): <K extends keyof T>(k: K) => T[K];
minTestCurry<Data>()("test").toUpperCase(); // okay
const dataTest = minTestCurry<Data>();
dataTest("test").toUpperCase(); // okay
declare function test<T>(): <B extends Path<T>>(name: B) => PathValue<T, B>;
const output = test<Data>()('test')