我正在尝试为接受三个参数的函数创建通用接口。填写第一个参数时,第二个参数的选项应在第一个参数的范围内。然后,第三个参数应在第二个参数的范围内。
我当前的代码如下:
type SettingActionCreator<T> = <
L extends T,
K extends keyof L,
C extends keyof L[K]
>(
type: K,
settingKey: keyof L[K],
settingValue: L[K][C]
)
export interface SomeSettings {
[Type.TypeA]: {
settingA: "value1" | "value2";
settingB: "value3 | "value4";
};
[Type.TypeB]: {
...
};
[Type.TypeC]: {
...
};
}
const setSomeSetting: SettingActionCreator<SomeSettings> = (
type,
settingKey,
settingValue
) =>
// do something
因此,当我想用参数调用setSomeSetting
时,我希望我传入的每个参数的作用域都会变小。
例如,如果我填写第一个参数,则SettingActionCreator确保第二个参数(settingKey
)只能是settingA
或settingB
。到目前为止,一切都按预期进行。
setSomeSetting(Type.TypeA, ....) // <-- settingKey accepts "settingA" and "settingB"
但是对于第三个论点,我似乎无法解决。当我设置第一个参数和第二个参数时,我希望第三个参数仅接受所选settingKey
参数中的并集选项。但是相反,我得到了Type.TypeA
中的所有选项。因此,settingA
和settingB
的settingValues
使用以下代码:
setSomeSetting(Type.TypeA, "settingA", "value3") // <-- settingValue should only accept "value1" or "value2"
我会期望出现类似以下错误:
TS2345: Argument of type '"value3"' is not assignable to parameter of type `"value1" | "value2"
但是相反,我没有类型错误,因为它同时接受settingA
和settingB
的值。
有人对我做错了什么建议吗?
答案 0 :(得分:3)
您需要向TypeScript证明SELECT to_char(u.created_at, 'YYYYmm') as yyyymm, COUNT(*)
FROM users u
WHERE u.created_at IS NOT NULL
GROUP BY yyyymm
ORDER BY yyyymm;
与settingKey
相关-声明中的settingValue
使它感到困惑(我不确定为什么-它感觉就像一个settingKey: keyof L[K]
的错误,但这绝对是对类型推断代码的一种限制)。
将该参数的类型更改为type C extends keyof L[K] != keyof L[K]
,TypeScript将能够理解三个参数之间的关系:
settingKey: C
这会导致您正在寻找的错误类型:
type SettingActionCreator<T> = <
L extends T,
K extends keyof L,
C extends keyof L[K]
>(
type: K,
settingKey: C, // <-- changed from keyof L[K]
settingValue: L[K][C]
) => void;
declare const Type: {
readonly TypeA: unique symbol,
readonly TypeB: unique symbol,
readonly TypeC: unique symbol
}
export interface SomeSettings {
[Type.TypeA]: {
settingA1: "valueA1" | "valueA2";
settingA2: "valueA3" | "valueA4";
},
[Type.TypeB]: {
settingB1: "valueB1" | "valueB2",
settingB2: "valueB3" | "valueB4"
},
[Type.TypeC]: {
//
}
}
const setSomeSetting: SettingActionCreator<SomeSettings> = (
type,
settingKey,
settingValue
) => {}