动态分配给字符串键打字稿错误没有找到参数类型为 'string' 的索引签名
Dynamically assign to string key typescript error No index signature with a parameter of type 'string' was found
我很难处理 redux reducer 中的这个打字稿错误。我创建了一个简化版本来重现这个问题。
export const CATEGORY_TYPES = ['cars', 'ships'] as const;
export type CategoryTypes = typeof CATEGORY_TYPES[number]
export interface ObjectArray {
externalId: string
}
export interface CarFilters {
arrayType: string[];
objectType: ObjectArray[];
}
export interface AppState {
appliedFilters: {
cars: CarFilters;
ships: {
[filter: string]: string[];
};
};
}
export interface AssignValue {
category: CategoryTypes;
key: string;
value: string[] | ObjectArray[];
}
const initialState = {
appliedFilters: {
cars: {
arrayType: [],
objectType: [],
},
ships: {},
},
} as AppState;
const assignValue = (params: AssignValue)=>{
initialState.appliedFilters[params.category][params.key] = params.value;
}
我遇到以下错误
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'CarFilters | { [filter: string]: string[]; }'.
No index signature with a parameter of type 'string' was found on type 'CarFilters | { [filter: string]: string[]; }'.
AssignValue
是 reducer ( redux-toolkit ) 中代码的复制。问题似乎是 [params.key]
。但是两个对象都有字符串键。
打字稿游乐场sample
这里可能有什么问题。
根据答案中的建议进行更新,因此以下内容完美无缺。
export const CATEGORY_TYPES = ['cars', 'ships'] as const;
export type CategoryTypes = typeof CATEGORY_TYPES[number];
export interface ObjectArray {
externalId: string
}
export interface CarFilters {
arrayType: string[];
objectType: ObjectArray[];
}
export interface ShipFilters {
[filter: string]: string;
}
export interface AppState {
appliedFilters: {
cars: CarFilters;
ships: ShipFilters;
};
}
const initialState = {
appliedFilters: {
cars: {
arrayType: [],
objectType: [],
},
ships: {},
},
} as AppState;
type AppStateFilters = AppState["appliedFilters"]
type PathValue<T extends object, K extends keyof T> = T[K] extends unknown ? T[K] : never
function assignValue<
Category extends keyof AppStateFilters,
Key extends keyof PathValue<AppStateFilters, Category>
>(params: {
category: Category,
key: Key,
value: PathValue<AppStateFilters[Category], Key>
}): void {
initialState.appliedFilters[params.category][params.key] = params.value;
}
然后我尝试将assignValue
函数的类型定义为一个单独的类型(实际上这是一个redux状态更新场景的简化示例,所以我需要为动作单独定义传递参数类型。 ) 而这次我想用相应的值( CarFilters 或 ShipFilters )更新整个类别(汽车或轮船)
// It works type defined with the function
const updateCategoryFilterV1 = <
Category extends keyof AppStateFilters,
Key extends PathValue<AppStateFilters, Category> = PathValue<AppStateFilters, Category>
>(params: {
category: Category,
value: Key
})=>{
initialState.appliedFilters[params.category] = params.value;
}
// But when type is extracted, it does not.
type UpdateAppliedFilterType<Category extends keyof AppStateFilters = keyof AppStateFilters,
Filter extends PathValue<AppStateFilters, Category> = PathValue<AppStateFilters, Category>> = {
category: Category,
filter: Filter
}
const updateCategoryFilterV2 = (params: UpdateAppliedFilterType) => {
initialState.appliedFilters[params.category] = params.filter
}
错误
Type 'CarFilters | ShipFilters' is not assignable to type 'CarFilters & ShipFilters'.
Type 'CarFilters' is not assignable to type 'CarFilters & ShipFilters'.
Type 'CarFilters' is not assignable to type 'ShipFilters'.
Index signature is missing in type 'CarFilters'.(2322)
The problem seems to be the [params.key]
. But both objects have string keys.
AppState['ships']
的定义说anystring
都可以作为key。那是一个 index signature.
另一方面,CarFilters
的定义说只有两个特定的字符串可以用作键。它没有索引签名。
如果 params.category
是 'cars'
,那么 params.key
必须是 'arrayType' | 'objectType'
。只是 string
不够具体。
同样,value: string[] | ObjectArray[];
不够具体,因为它不能确保您将正确的值分配给正确的键。
以下示例与您的 AssignValue
类型匹配,但未将正确的值分配给正确的路径:
const bad1: AssignValue = {
category: 'cars',
key: 'objectType',
value: ['a', 'b'] // assigns string[] where ObjectArray[] is expected
}
const bad2: AssignValue = {
category: 'cars',
key: 'someString', // unknown property key
value: ['a', 'b']
}
我可以改进您的 AssignValue
类型,使您只能传入有效参数。上面的 bad1
和 bad2
现在是错误。我正在使用映射类型、索引访问类型和联合类型。
type AssignCarFilter = {
[K in keyof CarFilters]: {
category: 'cars';
key: K;
value: CarFilters[K];
}
}[keyof CarFilters];
type AssignShipsFilter = {
category: 'ships';
key: string;
value: string[];
}
export type AssignValue = AssignCarFilter | AssignShipsFilter;
不幸的是,这并不能使错误消失。 TypeScript 很难理解分配键和分配值之间的关系。
所以现在至少我 as any
正在摆脱困境,并称之为改进。
const assignValue = (params: AssignValue) => {
(initialState as any).appliedFilters[params.category][params.key] = params.value;
}
如前所述您的'AssignValue'界面过于模糊。它不适合表示您试图强加给您的函数的关于键值对应的不变量。
但是,通过一些仪式,正确输入 assignValue
函数绝对是可能的。使用 distributive conditional types:
type AppStateFilters = AppState["appliedFilters"]
type PathValue<T extends object, K extends keyof T> = T[K] extends unknown ? T[K] : never
function assignValue<
Category extends keyof AppStateFilters,
Key extends keyof PathValue<AppStateFilters, Category>
>(params: {
category: Category,
key: Key,
value: PathValue<AppStateFilters[Category], Key>
}): void {
initialState.appliedFilters[params.category][params.key] = params.value;
}
我很难处理 redux reducer 中的这个打字稿错误。我创建了一个简化版本来重现这个问题。
export const CATEGORY_TYPES = ['cars', 'ships'] as const;
export type CategoryTypes = typeof CATEGORY_TYPES[number]
export interface ObjectArray {
externalId: string
}
export interface CarFilters {
arrayType: string[];
objectType: ObjectArray[];
}
export interface AppState {
appliedFilters: {
cars: CarFilters;
ships: {
[filter: string]: string[];
};
};
}
export interface AssignValue {
category: CategoryTypes;
key: string;
value: string[] | ObjectArray[];
}
const initialState = {
appliedFilters: {
cars: {
arrayType: [],
objectType: [],
},
ships: {},
},
} as AppState;
const assignValue = (params: AssignValue)=>{
initialState.appliedFilters[params.category][params.key] = params.value;
}
我遇到以下错误
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'CarFilters | { [filter: string]: string[]; }'.
No index signature with a parameter of type 'string' was found on type 'CarFilters | { [filter: string]: string[]; }'.
AssignValue
是 reducer ( redux-toolkit ) 中代码的复制。问题似乎是 [params.key]
。但是两个对象都有字符串键。
打字稿游乐场sample
这里可能有什么问题。
根据答案中的建议进行更新,因此以下内容完美无缺。
export const CATEGORY_TYPES = ['cars', 'ships'] as const;
export type CategoryTypes = typeof CATEGORY_TYPES[number];
export interface ObjectArray {
externalId: string
}
export interface CarFilters {
arrayType: string[];
objectType: ObjectArray[];
}
export interface ShipFilters {
[filter: string]: string;
}
export interface AppState {
appliedFilters: {
cars: CarFilters;
ships: ShipFilters;
};
}
const initialState = {
appliedFilters: {
cars: {
arrayType: [],
objectType: [],
},
ships: {},
},
} as AppState;
type AppStateFilters = AppState["appliedFilters"]
type PathValue<T extends object, K extends keyof T> = T[K] extends unknown ? T[K] : never
function assignValue<
Category extends keyof AppStateFilters,
Key extends keyof PathValue<AppStateFilters, Category>
>(params: {
category: Category,
key: Key,
value: PathValue<AppStateFilters[Category], Key>
}): void {
initialState.appliedFilters[params.category][params.key] = params.value;
}
然后我尝试将assignValue
函数的类型定义为一个单独的类型(实际上这是一个redux状态更新场景的简化示例,所以我需要为动作单独定义传递参数类型。 ) 而这次我想用相应的值( CarFilters 或 ShipFilters )更新整个类别(汽车或轮船)
// It works type defined with the function
const updateCategoryFilterV1 = <
Category extends keyof AppStateFilters,
Key extends PathValue<AppStateFilters, Category> = PathValue<AppStateFilters, Category>
>(params: {
category: Category,
value: Key
})=>{
initialState.appliedFilters[params.category] = params.value;
}
// But when type is extracted, it does not.
type UpdateAppliedFilterType<Category extends keyof AppStateFilters = keyof AppStateFilters,
Filter extends PathValue<AppStateFilters, Category> = PathValue<AppStateFilters, Category>> = {
category: Category,
filter: Filter
}
const updateCategoryFilterV2 = (params: UpdateAppliedFilterType) => {
initialState.appliedFilters[params.category] = params.filter
}
错误
Type 'CarFilters | ShipFilters' is not assignable to type 'CarFilters & ShipFilters'.
Type 'CarFilters' is not assignable to type 'CarFilters & ShipFilters'.
Type 'CarFilters' is not assignable to type 'ShipFilters'.
Index signature is missing in type 'CarFilters'.(2322)
The problem seems to be the
[params.key]
. But both objects have string keys.
AppState['ships']
的定义说anystring
都可以作为key。那是一个 index signature.
另一方面,CarFilters
的定义说只有两个特定的字符串可以用作键。它没有索引签名。
如果 params.category
是 'cars'
,那么 params.key
必须是 'arrayType' | 'objectType'
。只是 string
不够具体。
同样,value: string[] | ObjectArray[];
不够具体,因为它不能确保您将正确的值分配给正确的键。
以下示例与您的 AssignValue
类型匹配,但未将正确的值分配给正确的路径:
const bad1: AssignValue = {
category: 'cars',
key: 'objectType',
value: ['a', 'b'] // assigns string[] where ObjectArray[] is expected
}
const bad2: AssignValue = {
category: 'cars',
key: 'someString', // unknown property key
value: ['a', 'b']
}
我可以改进您的 AssignValue
类型,使您只能传入有效参数。上面的 bad1
和 bad2
现在是错误。我正在使用映射类型、索引访问类型和联合类型。
type AssignCarFilter = {
[K in keyof CarFilters]: {
category: 'cars';
key: K;
value: CarFilters[K];
}
}[keyof CarFilters];
type AssignShipsFilter = {
category: 'ships';
key: string;
value: string[];
}
export type AssignValue = AssignCarFilter | AssignShipsFilter;
不幸的是,这并不能使错误消失。 TypeScript 很难理解分配键和分配值之间的关系。
所以现在至少我 as any
正在摆脱困境,并称之为改进。
const assignValue = (params: AssignValue) => {
(initialState as any).appliedFilters[params.category][params.key] = params.value;
}
如前所述
但是,通过一些仪式,正确输入 assignValue
函数绝对是可能的。使用 distributive conditional types:
type AppStateFilters = AppState["appliedFilters"]
type PathValue<T extends object, K extends keyof T> = T[K] extends unknown ? T[K] : never
function assignValue<
Category extends keyof AppStateFilters,
Key extends keyof PathValue<AppStateFilters, Category>
>(params: {
category: Category,
key: Key,
value: PathValue<AppStateFilters[Category], Key>
}): void {
initialState.appliedFilters[params.category][params.key] = params.value;
}