当 A 和 O 都是对象的属性时,使用字符串数组 A 的值作为对象 O 中的键
Use values of string array A as keys in object O when A and O are both properties of an object
我想创建一个对象类型,具有 values
和 valuesMap
属性。 values
应该是一个字符串数组,valuesMap
应该是一个对象,其键是 values
中的条目,其值是字符串或布尔值。我正在努力在打字稿中定义这种类型约束。这是我尝试过的:
type FilterOptionBase<K extends string> = {
name: string;
values: K[];
multiselect: boolean;
isBoolean?: boolean;
valuesMap?: {
[key in K]: string | boolean;
};
};
type FilterOption = FilterOptionBase<string>
const myBadFilter: FilterOption = {
name: 'Status',
values: ["Online", "Offline"],
multiselect: false,
valuesMap: {
Online: true,
NotSure: false // <------ should error but doesnt
}
}
TypeScript playground
我觉得这应该比较简单,但解决方案却让我望而却步。如果之前有人问过这个问题,请将我带到正确的地方!
还有:
如果 isBoolean
定义为 true
,我们是否也可以将 valueMap
的值限制为布尔值,而不是 boolean | string
?
您的示例不起作用的原因是:
type FilterOption = FilterOptionBase<string>
...正在将 string
传递给 FilterOptionBase
,本质上是这样做的:
type FilterOptionBase = {
name: string;
values: string[];
multiselect: boolean;
isBoolean?: boolean;
valuesMap?: {
[key in string]: string | boolean;
};
};
因此,要正确键入它,您需要传入使用该类型时期望的字符串列表,如下所示:
const myBadFilter: FilterOptionBase<"Online" | "Offline"> = {
name: 'Status',
values: ["Online", "Offline"],
multiselect: false,
valuesMap: {
Online: true,
NotSure: false // <------ errors now!
}
}
但是,我认为您实际上 试图做的是使用 FilterOptionBase
类型作为各种不同对象的模板,并且不幸的是,没有办法那样做。你不能拥有一个既从自身读取又约束自身的类型。
但是您可以访问传递到函数的对象上的值,所以这是我在过去效果很好:
const filterFactory = <K extends string>(v: FilterOptionBase<K>) => v
const myBadFilter = filterFactory({
name: 'Status',
values: ['Online', 'Offline'],
multiselect: false,
valuesMap: {
Online: true,
NotSure: false, // <------ it's an error!
}
})
“也”回答
是的,可以根据 isBoolean
为 true
来更改它。你只需要做一个联合:
type foo = {
isBoolean: true
value: boolean
} | {
isBoolean: false
value: string
}
虽然它确实变得有点棘手,因为您必须使用工厂函数来解决问题。在这里:
type FilterOptionBase<
K extends string,
B extends boolean | undefined,
> = B extends true
? {
name: string
values: K[]
multiselect: boolean
isBoolean: B
valuesMap?: {
[key in K]: boolean
}
}
: {
name: string
values: K[]
multiselect: boolean
isBoolean?: B
valuesMap?: {
[key in K]: string
}
}
const filterFactory = <K extends string, B extends boolean | undefined>(
v: FilterOptionBase<K, B>,
) => v
const myBadFilter = filterFactory({
name: "Status",
values: ["Online", "Offline"],
multiselect: false,
isBoolean: true,
valuesMap: {
Online: true,
Offline: "foo", // <------ also an error!
},
})
const myOtherBadFilter = filterFactory({
name: "Status",
values: ["Online", "Offline"],
multiselect: false,
isBoolean: false,
valuesMap: {
Online: true, // <------ also an error!
Offline: "foo",
},
})
我想创建一个对象类型,具有 values
和 valuesMap
属性。 values
应该是一个字符串数组,valuesMap
应该是一个对象,其键是 values
中的条目,其值是字符串或布尔值。我正在努力在打字稿中定义这种类型约束。这是我尝试过的:
type FilterOptionBase<K extends string> = {
name: string;
values: K[];
multiselect: boolean;
isBoolean?: boolean;
valuesMap?: {
[key in K]: string | boolean;
};
};
type FilterOption = FilterOptionBase<string>
const myBadFilter: FilterOption = {
name: 'Status',
values: ["Online", "Offline"],
multiselect: false,
valuesMap: {
Online: true,
NotSure: false // <------ should error but doesnt
}
}
TypeScript playground
我觉得这应该比较简单,但解决方案却让我望而却步。如果之前有人问过这个问题,请将我带到正确的地方!
还有:
如果 isBoolean
定义为 true
,我们是否也可以将 valueMap
的值限制为布尔值,而不是 boolean | string
?
您的示例不起作用的原因是:
type FilterOption = FilterOptionBase<string>
...正在将 string
传递给 FilterOptionBase
,本质上是这样做的:
type FilterOptionBase = {
name: string;
values: string[];
multiselect: boolean;
isBoolean?: boolean;
valuesMap?: {
[key in string]: string | boolean;
};
};
因此,要正确键入它,您需要传入使用该类型时期望的字符串列表,如下所示:
const myBadFilter: FilterOptionBase<"Online" | "Offline"> = {
name: 'Status',
values: ["Online", "Offline"],
multiselect: false,
valuesMap: {
Online: true,
NotSure: false // <------ errors now!
}
}
但是,我认为您实际上 试图做的是使用 FilterOptionBase
类型作为各种不同对象的模板,并且不幸的是,没有办法那样做。你不能拥有一个既从自身读取又约束自身的类型。
但是您可以访问传递到函数的对象上的值,所以这是我在过去效果很好:
const filterFactory = <K extends string>(v: FilterOptionBase<K>) => v
const myBadFilter = filterFactory({
name: 'Status',
values: ['Online', 'Offline'],
multiselect: false,
valuesMap: {
Online: true,
NotSure: false, // <------ it's an error!
}
})
“也”回答
是的,可以根据 isBoolean
为 true
来更改它。你只需要做一个联合:
type foo = {
isBoolean: true
value: boolean
} | {
isBoolean: false
value: string
}
虽然它确实变得有点棘手,因为您必须使用工厂函数来解决问题。在这里:
type FilterOptionBase<
K extends string,
B extends boolean | undefined,
> = B extends true
? {
name: string
values: K[]
multiselect: boolean
isBoolean: B
valuesMap?: {
[key in K]: boolean
}
}
: {
name: string
values: K[]
multiselect: boolean
isBoolean?: B
valuesMap?: {
[key in K]: string
}
}
const filterFactory = <K extends string, B extends boolean | undefined>(
v: FilterOptionBase<K, B>,
) => v
const myBadFilter = filterFactory({
name: "Status",
values: ["Online", "Offline"],
multiselect: false,
isBoolean: true,
valuesMap: {
Online: true,
Offline: "foo", // <------ also an error!
},
})
const myOtherBadFilter = filterFactory({
name: "Status",
values: ["Online", "Offline"],
multiselect: false,
isBoolean: false,
valuesMap: {
Online: true, // <------ also an error!
Offline: "foo",
},
})