// Detecta tema escuro var iframe = document.getElementById('tweet-1840346445334864141-950'); if (document.body.className.includes('dark-theme')) { iframe.src = \\\"https://platform.twitter.com/embed/Tweet.html?id=1840346445334864141&theme=dark\\\" }
podemos chegar a... ??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(\\\"PROVEDOR A\\\", { ... });conectar(\\\"PROVEDOR B\\\", { ... }); ^ o preenchimento automático funciona ✅
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... }); ^ autocomplete works ✅Então, estamos desestruturando uma tupla (array) com os tipos exatos que queremos.A única desvantagem, se formos exigentes, adicionando mais pares à tupla... podemos extrair um tipo genérico aqui:
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(\\\"PROVEDOR A\\\", { ... });conectar(\\\"PROVEDOR B\\\", { ... }); ^ o preenchimento automático funciona ✅
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... }); ^ autocomplete works ✅7.TL;DR. COPIAR COLAR, OBRIGADOtipo Provedor = \\\"PROVEDOR A\\\" | “PROVEDOR B”;digite ProviderAOpts={...};digite ProviderBOpts={...};digite ProviderOpts = { \\\"PROVEDOR A\\\": ProviderAOpts; \\\"PROVEDOR B\\\": ProviderBOpts;};// tipo aux para extrair a chave e as opções de ProviderOptsdigite KeyOpts
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(\\\"PROVEDOR A\\\", { ... });conectar(\\\"PROVEDOR B\\\", { ... }); ^ o preenchimento automático funciona ✅
connect(\\\"PROVIDER A\\\", { ... });connect(\\\"PROVIDER B\\\", { ... }); ^ autocomplete works ✅
","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"}}
Há um cenário em que esse sentimento é particularmente intenso: quando uma função recebe um parâmetro que depende de qual "modo" está ativo.
mais claro com algum código de exemplo:
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 } }
(Tentei usar nomes mais realistas em vez de foo, goo, dog e cat).
Se você já passou algum tempo com TypeScript, pode suspeitar que costumávamos lidar com isso como ProviderAOpts, como ProviderBOpts.
Mas chega um momento em que você bate o punho na mesa e diz: "Chega!"
A primeira coisa que sempre me vem à mente nesses casos é usar sobrecarga de funções:
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) ❌ } }
O que não funciona. A assinatura da função não é inferida corretamente. O parâmetro options é sempre ProviderAOpts | ProvedorBOpts. que resolverá para a união comum.
Ts não vincula ambos os parâmetros corretamente.
A próxima ferramenta que experimento é Type Predicates:
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)) { ... } } ... }
Mas sinceramente, não resolvemos nada. Acabamos de mover o como para debaixo do tapete? Introduzimos ifs extras e ainda não estamos vinculando os parâmetros.
Genéricos. Tentei usar genéricos para vincular os parâmetros. Não funciona:
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) ❌ } }
Eu tentei tanto e cheguei tão longe
Mas no final, isso nem importa
Eu tive que cair para perder tudo
Mas no final, isso nem importa
??
Modificar os parâmetros opts adicionando o tipo de provedor resolve:
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 ✅ } }
Esta é a solução mais comum, mas nem sempre é possível alterar a assinatura da função. Ou talvez você simplesmente não queira . Questão de princípios?.
// Detecta tema escuro var iframe = document.getElementById('tweet-1840828253684056557-683'); if (document.body.className.includes('dark-theme')) { iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1840828253684056557&theme=dark" }
// Detecta tema escuro var iframe = document.getElementById('tweet-1840346445334864141-950'); if (document.body.className.includes('dark-theme')) { iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1840346445334864141&theme=dark" }
podemos chegar a... ??
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("PROVEDOR A", { ... }); conectar("PROVEDOR B", { ... }); ^ o preenchimento automático funciona ✅
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅Então, estamos desestruturando uma tupla (array) com os tipos exatos que queremos.
A única desvantagem, se formos exigentes, adicionando mais pares à tupla... podemos extrair um tipo genérico aqui:
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("PROVEDOR A", { ... }); conectar("PROVEDOR B", { ... }); ^ o preenchimento automático funciona ✅
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅7.TL;DR. COPIAR COLAR, OBRIGADO
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("PROVEDOR A", { ... }); conectar("PROVEDOR B", { ... }); ^ o preenchimento automático funciona ✅
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅
obrigado pela leitura?.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3