我正在尝试为函数参数创建一个类型,该类型基于type
字符串和可选的multiple
布尔值来限制其Record值:例如:
useQuery({
a: {
ref: ref(''), // ref is a string
type: 'string',
},
b: {
whitelist: [1, 2, 3], // whitelist is always optional and an array of the type
ref: ref([1, 2, 3]), // ref is a number array
type: 'number',
multiple: true,
},
});
因此,一个简单的方法是做类似下面的事情,但它不能完全工作,因为可选的多重布尔值没有正确地限制ref类型。
type DumbType = {
whitelist?: string[];
ref: Ref<string>;
type: 'string';
}
| {
whitelist?: string[];
ref: Ref<string[]>;
type: 'string';
multiple: true;
}
| {
whitelist?: number[];
ref: Ref<number>;
type: 'number';
}
| {
whitelist?: number[];
ref: Ref<number[]>;
type: 'number';
multiple: true;
}
| e.g.
useQuery({
type: 'string',
ref: ref(), // ref is inferred with string | string[] - without multiple: true
})
我试图使用Map类型来解决它,但是我被下面的问题卡住了。QueryOptions
本身似乎工作正常,但是UseQueryOptions
无法推断Record值的泛型。
type Primitives = 'string' | 'number' | 'boolean';
export type UseQueryOptions<T> = {
[K in keyof T]: QueryOptions<T[K]['type'], T[K]['multiple']>; // <= error
};
export type QueryOptions<T extends Primitives, M extends boolean | undefined> = {
whitelist?: StringTypeToType<T, true>;
ref: Ref<StringTypeToType<T, M>>;
type: T;
multiple?: M;
};
export type StringTypeToType<P extends Primitives, M extends boolean | undefined> = P extends 'string'
? ArrayWhenMultiple<M, string>
: P extends 'number'
? ArrayWhenMultiple<M, number>
: P extends 'boolean'
? ArrayWhenMultiple<M, boolean>
: never;
export type ArrayWhenMultiple<M extends boolean | undefined, T = any> = M extends true ? T[] : T;
export type TypeToRefType<P extends Primitives, M extends boolean> = Ref<StringTypeToType<P, M>>;
export const useQuery = <P extends Primitives, m extends boolean | undefined>(options: QueryOptions<P, M>) => {};
TSPlayground
1条答案
按热度按时间w46czmvw1#
为了简单起见,联合方法应该是首选的。但是在你的定义中有一些歧义,这会导致问题。编译器不能正确地区分联合,因为
multiple
属性只出现在一些组成部分中。在结构化类型系统中,类似于不会破坏当前联合类型的约定,因为大多数情况下允许多余的属性。
我们应该通过处理每个组成部分的
multiple
属性来消除这种不明确性。这可以通过禁止使用multiple?: undefined
设置该属性来实现,或者如果ref
类型为Ref<string[]>
或Ref<number[]>
,则键入 not set 或false
来实现。我认为允许false
值是有意义的。这就是它的样子:Playground