我们可以到达... ??
type Provider = \\\"PROVIDER A\\\" | \\\"PROVIDER B\\\";type ProviderAOpts = { ... };type ProviderBOpts = { ... };function connect( ...[provider, options]: | [\\\"PROVIDER A\\\", ProviderAOpts] | [\\\"PROVIDER B\\\", ProviderBOpts]) { switch (provider) { case \\\"PROVIDER A\\\": // options is ProviderAOpts ✅ case \\\"PROVIDER B\\\": // options is ProviderBOpts ✅ ... }}
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... }); ^ autocomplete works ✅
所以问题是我们正在用我们想要的确切类型解构一个元组(数组)。
唯一的缺点,如果我们很挑剔,可以向元组中添加更多对...我们可以在这里提取泛型类型:
type Provider = \\\"PROVIDER A\\\" | \\\"PROVIDER B\\\";type ProviderAOpts = { ... };type ProviderBOpts = { ... };type ProviderOpts = { \\\"PROVIDER A\\\": ProviderAOpts; \\\"PROVIDER B\\\": ProviderBOpts;};// solves to // [\\\"PROVIDER A\\\", ProviderAOpts] | [\\\"PROVIDER B\\\", ProviderBOpts]type ConnectOptions = { [K in keyof ProviderOpts]: [K, ProviderOpts[K]];}[keyof ProviderOpts]; function connect(...[provider, options]: ConnectOptions) { switch (provider) { case \\\"PROVIDER A\\\": // options is ProviderAOpts ✅ case \\\"PROVIDER B\\\": // options is ProviderBOpts ✅ ... }}
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... }); ^ autocomplete works ✅
type Provider = \\\"PROVIDER A\\\" | \\\"PROVIDER B\\\";type ProviderAOpts = { ... };type ProviderBOpts = { ... };type ProviderOpts = { \\\"PROVIDER A\\\": ProviderAOpts; \\\"PROVIDER B\\\": ProviderBOpts;};// aux type to extract the key and the options from ProviderOptstype KeyOpts= { [K in keyof T]: [K, T[K]];}[keyof T];function connect(...[provider, options]: KeyOpts ) { switch (provider) { case \\\"PROVIDER A\\\": // options is ProviderAOpts ✅ case \\\"PROVIDER B\\\": // options is ProviderBOpts ✅ ... }}
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... }); ^ autocomplete works ✅
感谢 Mateusz 和 Lenz 的帮助?.
感谢您的阅读?.
","image":"http://www.luping.net/uploads/20241104/17307234156728be5752a02.jpg","datePublished":"2024-11-07T10:48:39+08:00","dateModified":"2024-11-07T10:48:39+08:00","author":{"@type":"Person","name":"luping.net","url":"https://www.luping.net/articlelist/0_1.html"}}在一种情况下,这种感觉特别强烈:当函数采用的参数取决于哪个 "mode" 处于活动状态时。
通过一些示例代码更清晰:
type Provider = "PROVIDER A" | "PROVIDER B"; type ProviderAOpts = { ... }; type ProviderBOpts = { ... }; function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts) { switch (provider) { case "PROVIDER A": // options is ProviderAOpts case "PROVIDER B": // options is ProviderBOpts } }
(我尝试使用更现实的名称,而不是 foo、goo、dog 和 cat)。
如果您花了一些时间使用 TypeScript,您可能会怀疑我们过去使用 ProviderAOpts、ProviderBOpts 来处理此问题。
但有时你会用拳头猛击桌子并声称:“不再了!”
在这些情况下,我首先想到的是使用函数重载:
function connect(provider: "PROVIDER A", options: ProviderAOpts): void; function connect(provider: "PROVIDER B", options: ProviderBOpts): void; function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts) { switch (provider) { case "PROVIDER A": // (options as ProviderAOpts) ❌ case "PROVIDER B": // (options as ProviderBOpts) ❌ } }
这不起作用。函数签名未正确推断。 options 参数始终为 ProviderAOpts |提供者B选择。这将解决共同联盟。
Ts 未正确链接两个参数。
我尝试的下一个工具是 类型谓词:
type ConnectOptions = ProviderAOpts | ProviderBOpts; function isAOptions(options: ConnectOptions): options is ProviderAOpts { return (options as ProviderAOpts).$$$ !== undefined; } function isBOptions(options: ConnectOptions): options is ProviderBOpts { return (options as ProviderBOpts).$$$ !== undefined; } function connect(provider: Provider, options: ConnectOptions) { switch (provider) { case "PROVIDER A": if (isAOptions(options)) { ... } case "PROVIDER B": if (isBOptions(options)) { ... } } ... }
但老实说,我们没有解决任何问题。我们只是把 as 移到了地毯下?引入了额外的 ifs 并且,我们仍然没有链接参数。
泛型。我尝试使用泛型来链接参数。不起作用:
function connect( provider: T, options: T extends "PROVIDER A" ? ProviderAOpts : ProviderBOpts ) { switch (provider) { case "PROVIDER A": // (options as ProviderAOpts) ❌ case "PROVIDER B": // (options as ProviderBOpts) ❌ } }
我很努力,却走到了这一步
但最终,这并不重要
我必须跌倒才能失去一切
但最终,这并不重要
??
修改 opts 参数添加提供程序类型可以解决问题:
type Provider = "PROVIDER A" | "PROVIDER B"; type ProviderOptsBase = { provider: Provider; } type ProviderAOpts = ProviderOptsBase & { provider: "PROVIDER A"; ...; }; type ProviderBOpts = ProviderOptsBase & { provider: "PROVIDER B"; ...; }; function connect(options: ConnectOptions) { switch (options.provider) { case "PROVIDER A": // options is ProviderAOpts ✅ case "PROVIDER B": // options is ProviderBOpts ✅ } }
这是最常见的解决方案,但并不总是可以更改函数签名。或者也许你只是不想想要。原则问题?.
感谢 Mateusz Burzyński (@AndaristRake) 和 Lenz Weber (@phry)
我们可以到达... ??
type Provider = "PROVIDER A" | "PROVIDER B"; type ProviderAOpts = { ... }; type ProviderBOpts = { ... }; function connect( ...[provider, options]: | ["PROVIDER A", ProviderAOpts] | ["PROVIDER B", ProviderBOpts] ) { switch (provider) { case "PROVIDER A": // options is ProviderAOpts ✅ case "PROVIDER B": // options is ProviderBOpts ✅ ... } }
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅
所以问题是我们正在用我们想要的确切类型解构一个元组(数组)。
唯一的缺点,如果我们很挑剔,可以向元组中添加更多对...我们可以在这里提取泛型类型:
type Provider = "PROVIDER A" | "PROVIDER B"; type ProviderAOpts = { ... }; type ProviderBOpts = { ... }; type ProviderOpts = { "PROVIDER A": ProviderAOpts; "PROVIDER B": ProviderBOpts; }; // solves to // ["PROVIDER A", ProviderAOpts] | ["PROVIDER B", ProviderBOpts] type ConnectOptions = { [K in keyof ProviderOpts]: [K, ProviderOpts[K]]; }[keyof ProviderOpts]; function connect(...[provider, options]: ConnectOptions) { switch (provider) { case "PROVIDER A": // options is ProviderAOpts ✅ case "PROVIDER B": // options is ProviderBOpts ✅ ... } }
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅
type Provider = "PROVIDER A" | "PROVIDER B"; type ProviderAOpts = { ... }; type ProviderBOpts = { ... }; type ProviderOpts = { "PROVIDER A": ProviderAOpts; "PROVIDER B": ProviderBOpts; }; // aux type to extract the key and the options from ProviderOpts type KeyOpts= { [K in keyof T]: [K, T[K]]; }[keyof T]; function connect(...[provider, options]: KeyOpts ) { switch (provider) { case "PROVIDER A": // options is ProviderAOpts ✅ case "PROVIDER B": // options is ProviderBOpts ✅ ... } }
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅
感谢 Mateusz 和 Lenz 的帮助?.
感谢您的阅读?.
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3