어레이 속성을 중단하지 않고 TypeScript 딥 부분 매핑 유형을 구현하는 방법
TypeScript의 부분 매핑 유형을 인터페이스에 재귀적으로 적용하는 동시에 어레이 리턴 유형이 포함된 키를 중단하지 않는 방법에 대한 아이디어는?
다음 접근방식은 충분하지 않았다.
interface User {
emailAddress: string;
verification: {
verified: boolean;
verificationCode: string;
}
activeApps: string[];
}
type PartialUser = Partial<User>; // does not affect properties of verification
type PartialUser2 = DeepPartial<User>; // breaks activeApps' array return type;
export type DeepPartial<T> = {
[ P in keyof T ]?: DeepPartial<T[ P ]>;
}
좋은 생각 있어?
업데이트: 수락된 답변 - 현재로선 더 좋고 일반적인 해결책.
다음과 같이 유형과 맵핑된 유형 두 개가 교차하는 임시 해결 방법을 발견하였다.가장 눈에 띄는 단점은 배열 반품 유형이 있는 파손된 키를 복원하려면 속성 재정의를 제공해야 한다는 점이다.
예시
type PartialDeep<T> = {
[ P in keyof T ]?: PartialDeep<T[ P ]>;
}
type PartialRestoreArrays<K> = {
[ P in keyof K ]?: K[ P ];
}
export type DeepPartial<T, K> = PartialDeep<T> & PartialRestoreArrays<K>;
interface User {
emailAddress: string;
verification: {
verified: boolean;
verificationCode: string;
}
activeApps: string[];
}
export type AddDetailsPartialed = DeepPartial<User, {
activeApps?: string[];
}>
TS 2.8 및 조건부 유형을 사용하면 다음과 같이 간단히 작성할 수 있다.
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends Array<infer U>
? Array<DeepPartial<U>>
: T[P] extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: DeepPartial<T[P]>
};
또는 을 가지고[]
대신에Array<>
즉, 다음과 같다.
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends (infer U)[]
? DeepPartial<U>[]
: T[P] extends Readonly<infer U>[]
? Readonly<DeepPartial<U>>[]
: DeepPartial<T[P]>
};
당신은 이것과 다른 유용한 종류들에 대해 https://github.com/krzkaczor/ts-essentials 패키지를 체크아웃하는 것이 좋을 것이다.
업데이트 2018-06-22:
이 대답은 놀라운 조건부 유형 기능이 TypeScript 2.8에서 발표되기 1년 전에 작성되었다.그래서 이 대답은 더 이상 필요하지 않다.TypeScript 2.8 이상에서 이 동작을 얻는 방법은 아래 @krzystof-kaczor의 새로운 답변을 참조하십시오.
좋아, 여기 내가 미친것 같지만 완전히 일반적인 해결책(TypeScript 2.4 이상 필요)에 대한 최선의 시도가 있어. 그럴 가치가 없을지도 모르지만, 그것을 사용하고 싶다면, 내 손님이 되어라.
먼저, 우리는 몇 가지 유형 수준의 부울 논리가 필요하다.
type False = '0'
type True = '1'
type Bool = False | True
type IfElse<Cond extends Bool, Then, Else> = {'0': Else; '1': Then;}[Cond];
여기서 네가 알아야 할 건 그 타입이IfElse<True,A,B>
로 평가하다.A
그리고IfElse<False,A,B>
로 평가하다.B
.
이제 우리는 레코드 유형을 정의한다.Rec<K,V,X>
, 키가 있는 물체K
및 값 유형V
어디에Rec<K,V,True>
자산이 요구됨을 의미하며,Rec<K,V,False>
속성이 선택적임을 의미한다.
type Rec<K extends string, V, Required extends Bool> = IfElse<Required, Record<K, V>, Partial<Record<K, V>>>
이쯤 되면 자네에게 갈 수 있다.User
그리고DeepPartialUser
유형. 장군을 묘사해 보자.UserSchema<R>
우리가 신경쓰는 모든 재산은 필수적이거나 선택적이거나 둘 중 하나일 경우, 그 여부에 따라 달라진다.R
이다True
또는False
:
type UserSchema<R extends Bool> =
Rec<'emailAddress', string, R> &
Rec<'verification', (
Rec<'verified', boolean, R> &
Rec<'verificationCode', string, R>
), R> &
Rec<'activeApps', string[], R>
못생겼지?하지만 우리는 마침내 두 가지 모두를 설명할 수 있다.User
그리고DeepPartialUser
다음과 같이.
interface User extends UserSchema<True> { } // required
interface DeepPartialUser extends UserSchema<False> { } // optional
그리고 그것을 행동으로 보여라:
var user: User = {
emailAddress: 'foo@example.com',
verification: {
verified: true,
verificationCode: 'shazam'
},
activeApps: ['netflix','facebook','angrybirds']
} // any missing properties or extra will cause an error
var deepPartialUser: DeepPartialUser = {
emailAddress: 'bar@example.com',
verification: {
verified: false
}
} // missing properties are fine, extra will still error
여기 있다.그게 도움이 되길 바래!
나는 @krzystof의 대답으로 시작했지만, 그 이후 에지 케이스에 부딪히면 계속 반복해 왔다.특히 아래 에지 케이스는 주어진 기본 객체 값(즉,)에 기초한다.T[P]
):
any
any[]
ReadonlyArray<any>
Map
Set
type NonAny = number | boolean | string | symbol | null;
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends NonAny[] // checks for nested any[]
? T[P]
: T[P] extends ReadonlyArray<NonAny> // checks for nested ReadonlyArray<any>
? T[P]
: T[P] extends (infer U)[]
? DeepPartial<U>[]
: T[P] extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: T[P] extends Set<infer V> // checks for Sets
? Set<DeepPartial<V>>
: T[P] extends Map<infer K, infer V> // checks for Maps
? Map<K, DeepPartial<V>>
: T[P] extends NonAny // checks for primative values
? T[P]
: DeepPartial<T[P]>; // recurse for all non-array and non-primative values
};
그
NonAny
유형을 사용하여 확인any
가치
ts-toolbelt를 사용할 수 있고, 어떤 깊이에서도 타입에 대한 조작을 할 수 있다.
귀하의 경우 다음과 같은 것이 될 수 있다.
import {O} from 'ts-toolbelt'
interface User {
emailAddress: string;
verification: {
verified: boolean;
verificationCode: string;
}
activeApps: string[];
}
type optional = O.Optional<User, keyof User, 'deep'>
그리고 (디스플레이를 위해) 심층적으로 계산하려면Compute
그러기 위해서
'programing' 카테고리의 다른 글
Vue.js—v-model과 v-bind의 차이 (0) | 2022.03.14 |
---|---|
재료-UI의 탭과 반응 라우터 4의 통합? (0) | 2022.03.14 |
ASP에서 VueJS에 의한 경로 처리 방법.엔드포인트를 사용하는 NET Core? (0) | 2022.03.14 |
Python 3에서 웹에서 파일 다운로드 (0) | 2022.03.14 |
Firebase 함수 다시 쓰기 및 vue 라우터와의 충돌 (0) | 2022.03.13 |