결합 유형을 교차 유형으로 변환
유니언 타입을 교차 타입으로 변환하는 방법이 있습니까?
type FunctionUnion = (() => void) | ((p: string) => void)
type FunctionIntersection = (() => void) & ((p: string) => void)
변형을 적용하려고 합니다.FunctionUnion
갖기 위해FunctionIntersection
조합이 교차로 진입하길 바라나?분포 조건형이나 조건형으로부터의 추론이 그렇게 할 수 있습니다.(하지만 교차점에서 결합으로 하는 것은 불가능하다고 생각합니다만, 죄송합니다) 여기 사악한 마법이 있습니다:
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
그것은 유니언을 분배한다.U
모든 동의자들이 서로 반하는 위치에 있는 새로운 연합체로 다시 포장하는 거죠유형을 교차점으로 추론할 수 있습니다.I
핸드북에 기재되어 있는 바와 같이:
마찬가지로, 반변수 위치에 있는 동일한 유형 변수에 대해 여러 후보가 있으면 교차 유형이 유추됩니다.
효과가 있는지 봅시다.
먼저 괄호 안에 넣겠습니다.FunctionUnion
그리고.FunctionIntersection
왜냐하면 TypeScript는 함수 반환보다 결합/교차를 더 엄격하게 바인드하는 것처럼 보이기 때문입니다.
type FunctionUnion = (() => void) | ((p: string) => void);
type FunctionIntersection = (() => void) & ((p: string) => void);
테스트:
type SynthesizedFunctionIntersection = UnionToIntersection<FunctionUnion>
// inspects as
// type SynthesizedFunctionIntersection = (() => void) & ((p: string) => void)
맛있겠다!
일반적으로는 주의해 주세요.UnionToIntersection<>
는 TypeScript가 실제 결합이라고 생각하는 몇 가지 세부사항을 공개합니다.예를들면,boolean
분명히 내부적으로는 로 표현된다.true | false
,그렇게
type Weird = UnionToIntersection<string | number | boolean>
된다
type Weird = string & number & true & false
TS3.6+ 에서는, 이 기능이 매우 큰폭으로 삭감됩니다.
type Weird = never
가치관을 갖는다는 것은 불가능하기 때문입니다.string
그리고. number
그리고. true
그리고. false
.
또한 여러 유형의 교차로를 원하지만 결합을 반드시 교차로로 변환하지는 않을 때에도 매우 관련된 문제가 있습니다.임시 조합에 의지하지 않고는 교차로로 바로 갈 수 없어요!
문제는 우리가 교차로를 얻고자 하는 타입은 내부에 조합이 있고, 조합도 교차로로 전환될 수 있다는 것이다.구조를 위한 경비원:
// union to intersection converter by @jcalz
// Intersect<{ a: 1 } | { b: 2 }> = { a: 1 } & { b: 2 }
type Intersect<T> = (T extends any ? ((x: T) => 0) : never) extends ((x: infer R) => 0) ? R : never
// get keys of tuple
// TupleKeys<[string, string, string]> = 0 | 1 | 2
type TupleKeys<T extends any[]> = Exclude<keyof T, keyof []>
// apply { foo: ... } to every type in tuple
// Foo<[1, 2]> = { 0: { foo: 1 }, 1: { foo: 2 } }
type Foo<T extends any[]> = {
[K in TupleKeys<T>]: {foo: T[K]}
}
// get union of field types of an object (another answer by @jcalz again, I guess)
// Values<{ a: string, b: number }> = string | number
type Values<T> = T[keyof T]
// TS won't believe the result will always have a field "foo"
// so we have to check for it with a conditional first
type Unfoo<T> = T extends { foo: any } ? T["foo"] : never
// combine three helpers to get an intersection of all the item types
type IntersectItems<T extends any[]> = Unfoo<Intersect<Values<Foo<T>>>>
type Test = [
{ a: 1 } | { b: 2 },
{ c: 3 },
]
// this is what we wanted
type X = IntersectItems<Test> // { a: 1, c: 3 } | { b: 2, c: 3 }
// this is not what we wanted
type Y = Intersect<Test[number]> // { a: 1, b: 2, c: 3 }
이 예의 실행은 다음과 같습니다.
IntersectItems<[{ a: 1 } | { b: 2 }, { c: 3 }]> =
Unfoo<Intersect<Values<Foo<[{ a: 1 } | { b: 2 }, { c: 3 }]>>>> =
Unfoo<Intersect<Values<{0: { foo: { a: 1 } | { b: 2 } }, 1: { foo: { c: 3 } }}>>> =
Unfoo<Intersect<{ foo: { a: 1 } | { b: 2 } } | { foo: { c: 3 } }>> =
Unfoo<(({ foo: { a: 1 } | { b: 2 } } | { foo: { c: 3 } }) extends any ? ((x: T) => 0) : never) extends ((x: infer R) => 0) ? R : never> =
Unfoo<(({ foo: { a: 1 } | { b: 2 } } extends any ? ((x: T) => 0) : never) | ({ foo: { c: 3 } } extends any ? ((x: T) => 0) : never)) extends ((x: infer R) => 0) ? R : never> =
Unfoo<(((x: { foo: { a: 1 } | { b: 2 } }) => 0) | ((x: { foo: { c: 3 } }) => 0)) extends ((x: infer R) => 0) ? R : never> =
Unfoo<{ foo: { a: 1 } | { b: 2 } } & { foo: { c: 3 } }> =
({ foo: { a: 1 } | { b: 2 } } & { foo: { c: 3 } })["foo"] =
({ a: 1 } | { b: 2 }) & { c: 3 } =
{ a: 1 } & { c: 3 } | { b: 2 } & { c: 3 }
이것이 다른 유용한 기술도 보여주길 바란다.
나는 그가 설명한 부울 문제를 피하기 위해 @jcalz의 답변을 약간 확장했다.
type UnionToIntersectionHelper<U> = (
U extends unknown ? (k: U) => void : never
) extends (k: infer I) => void
? I
: never;
type UnionToIntersection<U> = boolean extends U
? UnionToIntersectionHelper<Exclude<U, boolean>> & boolean
: UnionToIntersectionHelper<U>;
기본적으로는 이 변환이 방해됩니다.true | false
완전히 숨어서true & false
보존,boolean
그 본질.
이제 정확하게 말할 것이다.UnionToIntersection<boolean>
이boolean
,것은 아니다.never
라고 하는 것은 맞지만,UnionToIntersection<boolean | string>
이never
기발한 라이브러리 유틸리티 타입에서 이용 가능 (2022/11년도 주간 150만건 다운로드)
또는 유사한 유형UnionToIntersection
(2022/11년도 주간 다운로드 1억1700만 건) 다른 보석 라이브러리 타입 페스트에서 다운로드.
다음과 같이 사용합니다.
import type { UnionToIntersection } from 'utility-types'
// or
import type { UnionToIntersection } from 'type-fest'
type FunctionUnion = (() => void) | ((p: string) => void)
type FunctionIntersection = UnionToIntersection<FunctionUnion>
// (() => void) & ((p: string) => void)
언급URL : https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type
'programing' 카테고리의 다른 글
이미지 크기를 추가할 때 get_the_post_post_url()이 작동하지 않음 (0) | 2023.03.27 |
---|---|
React propTypes: 오브젝트 오브 쉐이프? (0) | 2023.03.22 |
스프링 CORS 'Access-Control-Allow-Origin' 헤더가 없습니다. (0) | 2023.03.22 |
AngularJS 클라이언트 MVC 패턴? (0) | 2023.03.22 |
React 구성 요소 프로펠이 변경될 때 데이터를 가져오는 방법 (0) | 2023.03.22 |