Tutorial langkah demi langkah tentang cara menulis tipe generik di TypeScript yang menggabungkan struktur nilai kunci bertingkat arbitrer.
Catatan penerjemah: Saya sengaja tidak menerjemahkan beberapa kata (seperti generic, key-value), karena menurut saya hal ini hanya akan mempersulit pemahaman materi.
TLDR:
Kode sumber untuk DeepMergeTwoTypesakan ada di akhir artikel. Salin ke IDE Anda untuk dimainkan.
Bagaimana tampilannya di vsCode:
, generic- TypeScript, (Miniminalist Typescript - Generics)
IDE (. : TypeScript Playground ).
Disclaimer
production ( , ).
&- Typescript
. A B C, A & B
type A = { key1: string, key2: string }
type B = { key2: string, key3: string }
type C = A & B
const a = (c: C) => c., .
type A = { key1: string, key2: string }
type B = { key2: null, key3: string }
type C = A & B A key2 , B null.
Typescript never C . - :
type ExpectedType = {
key1: string | null,
key2: string,
key3: string
}generic-, Typescript. 2 generic-.
GetObjDifferentKeys<>
type GetObjDifferentKeys<T, U> = Omit<T, keyof U> & Omit<U, keyof T> 2 , A B.
type A = { key1: string, key2: string }
type B = { key2: null, key3: string }
type C = GetObjDifferentKeys<A, B>['']GetObjSameKeys<>
generic- , , .
type GetObjSameKeys<T, U> = Omit<T | U, keyof GetObjDifferentKeys<T, U>>โ .
type A = { key1: string, key2: string }
type B = { key2: null, key3: string }
type C = GetObjSameKeys<A, B> , generic- DeepMergeTwoTypes
DeepMergeTwoTypes<>
type DeepMergeTwoTypes<T, U> =
// " " () -
Partial<GetObjDifferentKeys<T, U>>
// -
& { [K in keyof GetObjSameKeys<T, U>]: T[K] | U[K] } generic " " T U, (). Partial<>, Typescript. ( &-) T U , T[K] | U[K].
. generic "-" (?), .
type A = { key1: string, key2: string }
type B = { key2: null, key3: string }
const fn = (c: DeepMergeTwoTypes<A, B>) => c. DeepMergeTwoTypes generic . generic MergeTwoObjects DeepMergeTwoTypes , .
// generic DeepMergeTwoTypes<>
type MergeTwoObjects<T, U> =
// " " () -
Partial<GetObjDifferentKeys<T, U>>
// -
& {[K in keyof GetObjSameKeys<T, U>]: DeepMergeTwoTypes<T[K], U[K]>}
export type DeepMergeTwoTypes<T, U> =
// ,
[T, U] extends [{ [key: string]: unknown }, { [key: string]: unknown } ]
? MergeTwoObjects<T, U>
: T | UPRO TIP: , DeepMergeTwoTypes if-else (extends ?:) T U , (tuple) [T, U]. &&- Javascript.
generic , { [key: string]: unknown } ( Object). , MergeTwoObject<>. .
: extends { [key: string]: unknown } -, .. , , booleans ...
! generic . :
type A = { key: { a: null, c: string} }
type B = { key: { a: string, b: string} }
const fn = (c: MergeTwoObjects<A, B>) => c.key.?
, . generic .
, , infer (to infer - ).
infer ( ). infer (Type inference in conditional types).
infer. (Item):
export type ArrayElement<A> = A extends (infer T)[] ? T : never
// Item === (number | string)
type Item = ArrayElement<(number | string)[]> , , . DeepMergeTwoTypes .
export type DeepMergeTwoTypes<T, U> =
// ----- 2 ------
// โฌ
[T, U] extends [(infer TItem)[], (infer UItem)[]]
// ... โฌ
? DeepMergeTwoTypes<TItem, UItem>[]
: ... rest of previous generic ... DeepMergeTwoTypes , .
type A = [{ key1: string, key2: string }]
type B = [{ key2: null, key3: string }]
const fn = (c: DeepMergeTwoTypes<A, B>) => c[0].! ?
... . Nullable non-nullable.
type A = { key1: string }
type B = { key1: undefined }
type C = DeepMergeTwoTypes<A, B>['key'] โ string | undefined, . if-else .
export type DeepMergeTwoTypes<T, U> =
[T, U] extends [(infer TItem)[], (infer UItem)[]]
? DeepMergeTwoTypes<TItem, UItem>[]
: [T, U] extends [{ [key: string]: unknown}, { [key: string]: unknown } ]
? MergeTwoObjects<T, U>
// ----- 2 ------
// โฌ
: [T, U] extends [
{ [key: string]: unknown } | undefined,
{ [key: string]: unknown } | undefined
]
// ... โฌ
? MergeTwoObjects<NonNullable<T>, NonNullable<U>> | undefined
: T | U nullable :
type A = { key1: string }
type B = { key1: undefined }
const fn = (c: DeepMergeTwoTypes<A, B>) => c.key1;... !
! nullable , .
generic :
type A = { key1: { a: { b: 'c'} }, key2: undefined }
type B = { key1: { a: {} }, key3: string }
const fn = (c: DeepMergeTwoTypes<A, B>) => c.:
/**
* 2 T U ,
* . `DeepMergeTwoTypes`
*/
type GetObjDifferentKeys<T, U> = Omit<T, keyof U> & Omit<U, keyof T>
/**
* 2 T and U
* `DeepMergeTwoTypes`
*/
type GetObjSameKeys<T, U> = Omit<T | U, keyof GetObjDifferentKeys<T, U>>
type MergeTwoObjects<T, U> =
// " "
Partial<GetObjDifferentKeys<T, U>>
// `DeepMergeTwoTypes<...>`
& { [K in keyof GetObjSameKeys<T, U>]: DeepMergeTwoTypes<T[K], U[K]> }
// 2
export type DeepMergeTwoTypes<T, U> =
// ,
//
[T, U] extends [(infer TItem)[], (infer UItem)[]]
? DeepMergeTwoTypes<TItem, UItem>[]
//
: [T, U] extends [
{ [key: string]: unknown},
{ [key: string]: unknown }
]
? MergeTwoObjects<T, U>
: [T, U] extends [
{ [key: string]: unknown } | undefined,
{ [key: string]: unknown } | undefined
]
? MergeTwoObjects<NonNullable<T>, NonNullable<U>> | undefined
: T | U
// :
type A = { key1: { a: { b: 'c'} }, key2: undefined }
type B = { key1: { a: {} }, key3: string }
const fn = (c: DeepMergeTwoTypes<A, B>) => c.keyBagaimana cara memperbaiki DeepMergeTwoTypes<T, U> generik sehingga bisa mengambil N argumen, bukan dua?
Saya akan meninggalkan hal ini untuk artikel berikutnya, tetapi Anda dapat melihat draf kerja saya di sini ).
Catatan penerjemah
Ini adalah pengalaman terjemahan pertama saya. Anda dengan hormat diminta untuk menulis secara pribadi tentang kesalahan ketik, koma, dan frasa yang diikat lidah.