通过传递的密钥访问通用数据
Access generic data via passed key
我有通用组件(类型如下):
const Search = <T extends object | number | string, K extends T extends object ? keyof T : T>(props: SearchProps<T,K>) => {
const { data, searchKey } = props;
return (
<div> Test </div>
)
};
export type SearchProps<T, K> = {
type: SearchType;
setSearcheData: Function;
data: T[];
searchKey: K;
};
您应该可以像示例中那样使用它:
const dataObject: dataObjectType = [
{
name: '1',
id: 1,
},
{
name: '2',
id: 2,
}
];
const dataString = ['1', '2'];
<Search
data={dataString}
searchKey={'string'}
type={SearchType.SingleIcon}
setSearcheData={()=>{}}
/>
我应该能够将 data
作为数组传递,并且 searchKey
就好像 T 是对象、它的键或只是一个类型一样。
但是当我尝试做类似
的事情时
data[0][`${searchKey}`]
我遇到了 TS 错误。
我试过
typeof data[0] === 'object' or Object.keys(data[0]).find(key => key === `${searchKey}`)
但是没用。
有什么想法吗?
我认为问题出在 Search()
的实现中。
这里有很多问题阻止编译器验证您正在做的事情是类型安全的。最后,您很可能需要放弃这种自动类型安全验证,并通过使用 type assertion.
告诉编译器不要担心它。
以下是我看到的问题:
在Search()
的实现中,props
的类型取决于未指定泛型类型参数T
和 K
;编译器可以很好地推断 指定的 类型的类型安全性,但是当它具有未指定的泛型(如 T
和 K
时,它就没有那么聪明了。具体来说,control flow analysis like type guarding, does not affect generic type parameters (see microsoft/TypeScript#24085 了解更多信息)。所以你可以尽可能多地测试 props
,它不会让编译器理解 T
应该被认为是可分配给 object
(而不是 object | string | number
)或者 K
应该被认为可以分配给 keyof T
.
在Search()
的实现中,K
的泛型约束是T extends object ? keyof T : T
,一个条件类型,它本身依赖于一个未指定的泛型类型参数T
。编译器尤其不擅长处理这种“未解析的条件类型”。 (有很多 GitHub 问题,这是根本问题;例如,您可以查看 microsoft/TypeScript#35257。)我的意思是,即使这样也行不通:
function foo<T>(t: T) {
const x: number extends T ? T : T = t; // error!
// Type 'T' is not assignable to type 'number extends T ? T : T'
}
如果编译器无法验证 number extends T ? T : T
与 T
本质上相同,那么它将无法处理这里更复杂的情况。
您已将 props
的属性分解为两个单独的变量 data
和 searchKey
。一旦这样做,编译器就会完全忘记它们彼此 相关 的事实。 (有关详细信息,请参阅 microsoft/TypeScript#30581)这意味着当您检查 typeof data[0] === "object"
时,编译器不会意识到它对 searchKey
的类型有任何影响。它将 data
和 searchKey
视为完全独立的变量。
为了判断K
是keyof T
还是T
,需要检查data[0]
还是props.data[0]
的类型为 object
、string
或 number
。这些类型不是“单一类型”,因此编译器不会将 props
视为 discriminated union,即使您可以将其类型写成 SearchProps<T, keyof T> | SearchProps<string | number, string | number>
。因此,没有很好的方法来利用在检查可区分联合的属性时获得的联合过滤。
所有这些放在一起意味着编译器确实没有能力为您验证类型安全。在这种情况下,你比编译器知道的更多,你应该使用类型断言:
const Search = <T extends object | number | string, K extends T extends object ? keyof T : T>(
props: SearchProps<T, K>
) => {
const { data, searchKey } = props;
if (typeof data[0] === 'object') {
data[0][searchKey as keyof T]
} else {
data.indexOf(searchKey as T);
}
};
在上面,searchKey as keyof T
和 searchKey as T
是类型断言,您告诉编译器您对 searchKey
的了解,它只会相信您并继续前进。那应该抑制错误。请注意,这给您带来了验证类型安全的负担,您应该认真对待这一责任,因为如果您进行了一些使您的假设无效的更改,您不能指望出现警告。例如,您可以将 (typeof data[0] === 'object')
更改为 (typeof data[0] !== 'object')
,编译器将不会注意到。所以要小心。
好的,希望对您有所帮助;祝你好运!
我有通用组件(类型如下):
const Search = <T extends object | number | string, K extends T extends object ? keyof T : T>(props: SearchProps<T,K>) => {
const { data, searchKey } = props;
return (
<div> Test </div>
)
};
export type SearchProps<T, K> = {
type: SearchType;
setSearcheData: Function;
data: T[];
searchKey: K;
};
您应该可以像示例中那样使用它:
const dataObject: dataObjectType = [
{
name: '1',
id: 1,
},
{
name: '2',
id: 2,
}
];
const dataString = ['1', '2'];
<Search
data={dataString}
searchKey={'string'}
type={SearchType.SingleIcon}
setSearcheData={()=>{}}
/>
我应该能够将 data
作为数组传递,并且 searchKey
就好像 T 是对象、它的键或只是一个类型一样。
但是当我尝试做类似
的事情时data[0][`${searchKey}`]
我遇到了 TS 错误。
我试过
typeof data[0] === 'object' or Object.keys(data[0]).find(key => key === `${searchKey}`)
但是没用。
有什么想法吗?
我认为问题出在 Search()
的实现中。
这里有很多问题阻止编译器验证您正在做的事情是类型安全的。最后,您很可能需要放弃这种自动类型安全验证,并通过使用 type assertion.
告诉编译器不要担心它。以下是我看到的问题:
在
Search()
的实现中,props
的类型取决于未指定泛型类型参数T
和K
;编译器可以很好地推断 指定的 类型的类型安全性,但是当它具有未指定的泛型(如T
和K
时,它就没有那么聪明了。具体来说,control flow analysis like type guarding, does not affect generic type parameters (see microsoft/TypeScript#24085 了解更多信息)。所以你可以尽可能多地测试props
,它不会让编译器理解T
应该被认为是可分配给object
(而不是object | string | number
)或者K
应该被认为可以分配给keyof T
.在
Search()
的实现中,K
的泛型约束是T extends object ? keyof T : T
,一个条件类型,它本身依赖于一个未指定的泛型类型参数T
。编译器尤其不擅长处理这种“未解析的条件类型”。 (有很多 GitHub 问题,这是根本问题;例如,您可以查看 microsoft/TypeScript#35257。)我的意思是,即使这样也行不通:function foo<T>(t: T) { const x: number extends T ? T : T = t; // error! // Type 'T' is not assignable to type 'number extends T ? T : T' }
如果编译器无法验证 number extends T ? T : T
与 T
本质上相同,那么它将无法处理这里更复杂的情况。
您已将
props
的属性分解为两个单独的变量data
和searchKey
。一旦这样做,编译器就会完全忘记它们彼此 相关 的事实。 (有关详细信息,请参阅 microsoft/TypeScript#30581)这意味着当您检查typeof data[0] === "object"
时,编译器不会意识到它对searchKey
的类型有任何影响。它将data
和searchKey
视为完全独立的变量。为了判断
K
是keyof T
还是T
,需要检查data[0]
还是props.data[0]
的类型为object
、string
或number
。这些类型不是“单一类型”,因此编译器不会将props
视为 discriminated union,即使您可以将其类型写成SearchProps<T, keyof T> | SearchProps<string | number, string | number>
。因此,没有很好的方法来利用在检查可区分联合的属性时获得的联合过滤。
所有这些放在一起意味着编译器确实没有能力为您验证类型安全。在这种情况下,你比编译器知道的更多,你应该使用类型断言:
const Search = <T extends object | number | string, K extends T extends object ? keyof T : T>(
props: SearchProps<T, K>
) => {
const { data, searchKey } = props;
if (typeof data[0] === 'object') {
data[0][searchKey as keyof T]
} else {
data.indexOf(searchKey as T);
}
};
在上面,searchKey as keyof T
和 searchKey as T
是类型断言,您告诉编译器您对 searchKey
的了解,它只会相信您并继续前进。那应该抑制错误。请注意,这给您带来了验证类型安全的负担,您应该认真对待这一责任,因为如果您进行了一些使您的假设无效的更改,您不能指望出现警告。例如,您可以将 (typeof data[0] === 'object')
更改为 (typeof data[0] !== 'object')
,编译器将不会注意到。所以要小心。
好的,希望对您有所帮助;祝你好运!