우리는...에 갈 수 있어요 ??


5. 작동하는 것: 구조화되지 않은 튜플

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 ✅

그래서 중요한 것은 우리가 원하는 정확한 유형으로 튜플(배열)을 분해한다는 것입니다.

유일한 단점은 튜플에 더 많은 쌍을 추가하는 것입니다. 여기에서 일반 유형을 추출할 수 있습니다.


6. 작동 방식: 일반화된 튜플 솔루션

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 ✅

7. 요약, 요약. 복사 붙여넣기, 감사합니다

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"}}
"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > 고급 Ts: 종속 매개변수, 추론된 결합 및 Twitter에서의 건전한 상호 작용.

고급 Ts: 종속 매개변수, 추론된 결합 및 Twitter에서의 건전한 상호 작용.

2024-11-07에 게시됨
검색:535

Advanced Ts: Dependent parameters, inferred unions and a healthy interaction on Twitter.

TypeScript에서 Foo로 글을 쓸 때마다 패배의 무게를 느낍니다.

이런 느낌이 특히 강렬한 시나리오가 하나 있습니다. 함수가 활성화된 "모드"에 따라 달라지는 매개변수를 취하는 경우입니다.

몇 가지 예제 코드로 더욱 명확해졌습니다.

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로 처리했다고 의심할 수 있습니다.


하지만 테이블을 주먹으로 내리치며 다음과 같이 주장할 때가 있습니다. "더 이상은 안돼!"


1. 작동하지 않는 것

이러한 경우에 항상 가장 먼저 떠오르는 것은 함수 오버로딩:
을 사용하는 것입니다.

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가 두 매개변수를 모두 올바르게 연결하지 않습니다.


2. 작동하지만 매개변수를 연결하지 않는 것

제가 시도하는 다음 도구는 유형 조건자:
입니다.

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)) {
        ...
      }
  }
  ...
}

하지만 솔직히 우리는 아무것도 해결하지 못했습니다. 우리는 방금 양탄자 아래로 옮겼습니까?. 추가 if를 도입했지만 아직 매개변수를 연결하지 않았습니다.


3. 안 되고 눈물이 나는 것

일반. 매개변수를 연결하기 위해 제네릭을 사용하려고 했습니다. 작동하지 않습니다:

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) ❌
  }
}

정말 열심히 노력해서 지금까지 왔습니다
하지만 결국에는 별 상관이 없습니다
모든 것을 잃어버리려면 넘어져야만 했어
하지만 결국에는 별 상관이 없습니다
?‍?


4. 작동하지만 함수 서명을 변경하도록 강요하는 것은 무엇입니까?

제공자 유형을 추가하여 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)에게 감사드립니다.

우리는...에 갈 수 있어요 ??


5. 작동하는 것: 구조화되지 않은 튜플

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 ✅

그래서 중요한 것은 우리가 원하는 정확한 유형으로 튜플(배열)을 분해한다는 것입니다.

유일한 단점은 튜플에 더 많은 쌍을 추가하는 것입니다. 여기에서 일반 유형을 추출할 수 있습니다.


6. 작동 방식: 일반화된 튜플 솔루션

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 ✅

7. 요약, 요약. 복사 붙여넣기, 감사합니다

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에게 감사드립니다.

읽어주셔서 감사합니다 ?.

릴리스 선언문 이 기사는 https://dev.to/manuartero/advanced-ts-dependent-parameters-inferred-unions-and-a-healthy-interaction-on-twitter-13bc?1에서 복제됩니다. 침해가 있는 경우, 문의 Study_golang@163 .comdelete
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3