【问题标题】:How do I tell TypeScript to allow only properties that have a string value as argument of a function [duplicate]如何告诉 TypeScript 只允许具有字符串值的属性作为函数的参数 [重复]
【发布时间】:2019-10-31 22:55:11
【问题描述】:

我想编写一个泛型函数,它以泛型类型的属性名称作为参数。我需要让 TypeScript 断言该属性的值是特定类型的。考虑以下简化代码:

interface MyObject {
 myProp: number;
 mySecondProp: string;
 myOtherProp: string;
 myFlagProp: boolean;
}

const doStuff<T> = (obj: T, propName: SomeType) => { /***/ }

我可以提取特定类型的所有属性(例如string),但编译器不会确切知道该属性的类型:

type StringProps<T> = { 
  [K in keyof T]: T[K] extends string ? K : never }[keyof T] 
}

const doStuff<T> = (obj: T, propName: StringProps<T>) => { 
  obj[propName].indexOf("a"); // Property 'indexOf' does not exist on type 'T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]'
}

我可以做些什么来让编译器明白它应该只接受字符串属性名称并且值总是string 类型?

【问题讨论】:

标签: typescript generics


【解决方案1】:

Typescript 通常不擅长推断仍然包含未解析类型参数的条件类型。因此,当您调用 StringProps&lt;T&gt; 时,很容易将其解析为函数内部 T 的字符串键,编译器不会尝试感知 T[StringProps&lt;T&gt;]

您可以通过其他方式指定参数。您可以为属性键使用另一个类型参数,并指定T 必须是Record&lt;K, string&gt;。这对于编译器来说会更简单:

type StringProps<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];
function doStuff<T>(obj: T, propName: StringProps<T>): void
function doStuff<K extends PropertyKey, T extends Record<K, string>>(obj: T, propName: K): void { 
    obj[propName].indexOf("a"); 
}

Play

你会注意到我也保留了你的签名,一个对调用站点上的智能感知表现更好,新签名对实施表现更好。

根据您在函数中执行多少索引,您可能最好只使用断言:

type StringProps<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];
function doStuff<T>(obj: T, propName: StringProps<T>): void{ 
    (obj[propName] as unknown as string).indexOf("a"); 
}

【讨论】:

    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2021-09-11
    • 2013-01-11
    • 2021-11-22
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-07-30
    相关资源
    最近更新 更多