이러한 느낌이 특히 강한 시나리오가 하나 있습니다. 함수가 활성화된 "모드"에 따라 매개변수를 사용하는 경우입니다.
몇 가지 예제 코드로 더욱 명확해졌습니다.
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) ❌ } }
작동하지 않습니다. 함수 서명이 올바르게 유추되지 않습니다. 옵션 매개변수는 항상 ProviderAOpts | ProviderBOpts. 이는 공동 연합으로 해결될 것입니다.
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)) { ... } } ... }
하지만 솔직히 우리는 아무것도 해결하지 못했습니다. 우리는 방금 양탄자 아래로 옮겼습니까?. 추가 ifs를 도입했지만 아직 매개변수를 연결하지 않았습니다.
제네릭. 매개변수를 연결하기 위해 제네릭을 사용하려고 했습니다. 작동하지 않습니다:
function connect<T extends Provider>( 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 ✅ ... } }5. 작동하는 것: 구조화되지 않은 튜플
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 ✅ ... } }6. 작동 방식: 일반화된 튜플 솔루션
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<T> = { [K in keyof T]: [K, T[K]]; }[keyof T]; function connect(...[provider, options]: KeyOpts<ProviderOpts>) { switch (provider) { case "PROVIDER A": // options is ProviderAOpts ✅ case "PROVIDER B": // options is ProviderBOpts ✅ ... } }7. 요약, 요약. 복사 붙여넣기, 감사합니다
connect("PROVIDER A", { ... }); connect("PROVIDER B", { ... }); ^ autocomplete works ✅
도움을 주신 Mateusz와 Lenz에게 감사드립니다.
읽어주셔서 감사합니다 ?. <script> // Detect dark theme 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" } </script> <script> // Detect dark theme 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" } </script>위 내용은 고급 Ts: 종속 매개변수, 추론된 결합 및 Twitter에서의 건전한 상호 작용.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!