我不明白为什么TS用这条消息抱怨return option[optionTextKey]个:

Type TTextKey cannot be used to index type TOption

代码:

type Props<
    TTextKey,
    TOption extends (TTextKey extends string ? { [key in TTextKey]: string; } : string),
> = (
    {
        optionTextKey: TTextKey;
        options: TOption[];
    }
    |
    {
        options: string[];
        optionTextKey?: never;
    }
) & {
    name: string;
    placeholder: string;
};

function LinkDropdown<
    TTextKey,
    TOption extends (TTextKey extends string ? { [key in TTextKey]: string; } : string),
>({
    options,
    optionTextKey,
    name,
    placeholder,
}: Props<TTextKey, TOption>): ReactElement
   // some code

    const getOptionText = (option: TOption, optionTextKey: TTextKey) => {
        if ('string' === typeof option) return option;
        // ts complains here
        return option[optionTextKey];
    };

   // some code
}

如果我这样赚TOption,这条消息就不存在了:

TOption extends TTextKey extends { [key in TTextKey]: string; }

upd

我怎么才能修好它呢?

推荐答案

问题在于,TypeScrip当前不能使用control flow analysis(例如,if/else判断)来缩小或重新设置constrain generic类型参数.在……里面

const getOptionText = (option: O, optionTextKey: K) => {
  if ('string' === typeof option) return option;      
  return option[optionTextKey];
};

显然,您希望判断option是否为string会对类型参数O产生一些影响,而这大概也会对类型参数K产生影响.但TypeScrip不是这样工作的.选中option只会影响option的类型,而不会影响O.实际上,您不能假设Ostring的子类型,因为它可能是wider.例如,option可能是string,但O实际上是union type string | {a: string}.目前,对于这样的判断,好的Typescript 无法对O做任何事情,所以它什么也做不了.然后,当第option[optionTextKey]行中的OK仍然不受影响时,就会出现错误.

GitHub中有许多开放的请求,试图获得更好的支持.可能与您的问题最相关的是microsoft/TypeScript#33912,它具体是关于泛型conditional types的,而且由于您的O被限制为依赖于泛型K的条件类型,所以这个缺失的特性至少是相关的.但是,即使实现了这一点,也可能不能解决您所面临的问题.至少就目前而言,如果您想要使用控制流分析来工作,您将不得不从泛型转向联合.


因此,编译代码的一种方法是用相关的具体联合类型替换泛型O:

const getOptionText = (
  option: string | { [P in K & string]: string },
  optionTextKey: K & string
) => {
  if ('string' === typeof option) return option;
  return option[optionTextKey];
};

现在,由于option是并集类型string | { ⋯ },所以typeof option的判断可以将option缩小到并集的任一侧. 如果是stringreturn option就是string如果是物体侧,那么option可以用optionTextKey索引. 请注意,我必须将optionTextKey的类型设置为intersection type K & string,以便将其用作键类型,因为您的K尚未受到这样的约束. 很可能有很多修改可以改进这里的代码示例,但我认为这超出了所问问题的范围. 我在这里展示的变化是我能想到的最小的变化.

Playground link to code

Typescript相关问答推荐

如何使用Generics保留构造函数的类型信息?

返回对象的TypScript构造函数隐式地替换This的值来替换super(.)的任何调用者?

如何将绑定到实例的类方法复制到类型脚本中的普通对象?

如何缩小变量访问的对象属性范围?

在键和值为ARGS的泛型函数中未正确推断类型

泛型类型,引用其具有不同类型的属性之一

我想创建一个只需要一个未定义属性的打字脚本类型

通过字符串索引访问对象';S的值时出现文字脚本错误

在HighChats列时间序列图中,十字准线未按预期工作

编译TypeScrip项目的一部分导致错误

try 呈现应用程序获取-错误:动作必须是普通对象.使用自定义中间件进行MySQL操作

如何为特定参数定义子路由?

如何在打字角react 式中补齐表格组

如何通过转换器类继承使用多态将对象从一种类型转换为另一种类型

如何使函数参数数组不相交?

参数未映射泛型返回类型

为什么我会得到一个;并不是所有的代码路径都返回一个值0;switch 中的所有情况何时返回或抛出?(来自vsCode/TypeScript)

TypeScript是否不知道其他函数内部的类型判断?

如何根据Typescript 中带有泛型的对象嵌套键数组获取数组或对象的正确类型?

元素隐式具有any类型,因为string类型的表达式不能用于索引类型{Categories: Element;管理员:元素; }'