Distributive Conditional Types
Distributive Conditional Types (có thể được gọi là kiểu điều kiện phân phối, phân phối union type, v.v.) chỉ tính chất khi Conditional Types được áp dụng cho generic type và type argument là union type, thì điều kiện sẽ được áp dụng riêng lẻ (= phân phối) cho từng thành viên cấu thành union type đó.
Ví dụ, có kiểu như sau:
tstypeToArray <T > =T extends any ?T [] : never;
tstypeToArray <T > =T extends any ?T [] : never;
Khi đó ToArray<number> là number[], ToArray<string> là string[], nhưng khi truyền union type number | string cho T, kết quả sẽ như sau:
tstypeNumOrStrArray =ToArray <number | string>;
tstypeNumOrStrArray =ToArray <number | string>;
Kiểu này được giải quyết theo luồng như sau:
Conditional Types được áp dụng cho generic type và union type (
number | string) được truyền vào, nên đáp ứng điều kiện phân phối.tstypeToArray <T > =T extends any ?T [] : never;typeNumOrStrArray =ToArray <number | string>;tstypeToArray <T > =T extends any ?T [] : never;typeNumOrStrArray =ToArray <number | string>;ToArrayđược phân phối cho từng phần tử riêng lẻ của union.tstypeNumOrStrArray =ToArray <number> |ToArray <string>;tstypeNumOrStrArray =ToArray <number> |ToArray <string>;Mỗi phần tử trở thành
number[]vàstring[], cuối cùng nhận được kiểunumber[] | string[].tstypeNumOrStrArray = number[] | string[];tstypeNumOrStrArray = number[] | string[];
Tính chất này chỉ xảy ra khi generics được sử dụng trong Conditional Types. Ví dụ, với type alias như sau, phân phối không xảy ra:
tstypeToArray2 <T > =T [];typeNumOrStrArray2 =ToArray2 <number | string>;
tstypeToArray2 <T > =T [];typeNumOrStrArray2 =ToArray2 <number | string>;
Việc phân phối có xảy ra hay không tạo ra sự khác biệt như sau, nên hãy sử dụng phù hợp với mục đích:
ts// 分配有りletnumOrStrArray :ToArray <number | string> = [1, 2, 3]; // OKnumOrStrArray = ["a", "b", "c"]; // OKType '(string | number)[]' is not assignable to type 'string[] | number[]'. Type '(string | number)[]' is not assignable to type 'string[]'. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.2322Type '(string | number)[]' is not assignable to type 'string[] | number[]'. Type '(string | number)[]' is not assignable to type 'string[]'. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.= [1, 2, "a"]; // NG numOrStrArray // 分配無しletnumOrStrArray2 :ToArray2 <number | string> = [1, 2, 3]; // OKnumOrStrArray2 = ["a", "b", "c"]; // OKnumOrStrArray2 = [1, 2, "a"]; // OK
ts// 分配有りletnumOrStrArray :ToArray <number | string> = [1, 2, 3]; // OKnumOrStrArray = ["a", "b", "c"]; // OKType '(string | number)[]' is not assignable to type 'string[] | number[]'. Type '(string | number)[]' is not assignable to type 'string[]'. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.2322Type '(string | number)[]' is not assignable to type 'string[] | number[]'. Type '(string | number)[]' is not assignable to type 'string[]'. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.= [1, 2, "a"]; // NG numOrStrArray // 分配無しletnumOrStrArray2 :ToArray2 <number | string> = [1, 2, 3]; // OKnumOrStrArray2 = ["a", "b", "c"]; // OKnumOrStrArray2 = [1, 2, "a"]; // OK
Cách ngăn chặn phân phối
Nếu muốn sử dụng Conditional Types nhưng không muốn phân phối, bạn có thể tránh phân phối bằng cách bao type variable trong [].
tstypeNotDistribute <T > = [T ] extends [string] ? true : false;
tstypeNotDistribute <T > = [T ] extends [string] ? true : false;
Kiểu NotDistribute này trả về true với kiểu string, nhưng trả về false với kiểu string | number. Bởi vì kiểu string | number không phải là subtype của kiểu string (tức là string | number extends string là false), nên false được trả về.
tstypeA =NotDistribute <string>;typeB =NotDistribute <number>;typeC =NotDistribute <string | number>;
tstypeA =NotDistribute <string>;typeB =NotDistribute <number>;typeC =NotDistribute <string | number>;