类型缩小只允许特定类型的属性 'keyof T'

问题描述

尝试使 keyof T 成为字符串返回类型,并且在尝试将属性传递到 tags 时似乎可以工作。虽然当将它用作索引时,它似乎并没有缩小它将成为一个字符串的范围。 错误Type 'T[KeyOfType<T,string>]' is not assignable to type 'string'. 我做错了什么还是打字稿限制?

type KeyOfType<T,U> = { [P in keyof T]: T[P] extends U ? P : never }[keyof T];


interface TagProps<T> {
    tags: T[];
    tagLabelKey: KeyOfType<T,string>;
}

const tag = [{
    id: 1,name: 'raw',}]

const tags = <T,>({tags,tagLabelKey}: TagProps<T>) => {
    const getLabel = (tag: T): string => {
        return tag[tagLabelKey];
    }
}

tags({ tags: tag,tagLabelKey: 'name' })

playground

解决方法

这确实似乎是一个打字稿限制。来自 this github issue 上的一位打字稿开发人员:

这里的问题是我们没有更高阶的推理来说明“如果一个键来自过滤掉不是字符串的键的操作,那么通过该键进行索引一定会产生一个字符串”。从 TS 的角度来看,FilterProperties 类型在逻辑上实际上是不透明的。

他甚至提出了一种实现相同语义的替代方法。转换为您的情况(并假设您想在数组上映射 getLabel 并返回结果):

interface TagProps<P extends string> {
    tags: Record<P,string>[];
    tagLabelKey: P;
}

const tags = <P extends string,>({tags,tagLabelKey}: TagProps<P>) => {
    const getLabel = (tag: Record<P,string>): string => {
        return tag[tagLabelKey];
    }
    return tags.map(getLabel)
}

const tag = [{
    id: 1,name: 'raw',}]

tags({ tags: tag,tagLabelKey: 'name' }) // typechecks
tags({ tags: tag,tagLabelKey: 'id' }) // does not typecheck

高级区别在于不是在标签对象类型中通用和提取字符串键(通过KeyOfType),在键中通用 strong> 并使用它构建标签对象的相关部分,同时只允许将字符串分配给它(通过 Record<P,string>)。

或者使用更少的显式类型和更多的类型推断:

interface TagProps<P extends string> {
    tags: Record<P,tagLabelKey}: TagProps<P>): string[] => {
    return tags.map((tag) => tag[tagLabelKey])
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...