Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: operations failed unless separated #16244

Closed
KiaraGrouwstra opened this issue Jun 3, 2017 · 3 comments
Closed

bug: operations failed unless separated #16244

KiaraGrouwstra opened this issue Jun 3, 2017 · 3 comments

Comments

@KiaraGrouwstra
Copy link
Contributor

KiaraGrouwstra commented Jun 3, 2017

TypeScript Version: 2.3.1-insiders.20170416 (Playground, strictNullChecks off)

Code

Omit type for #12215:

// helpers...
type Obj<T> = { [k: string]: T };
type SafeObj<O extends { [k: string]: any }, Name extends string, Param extends string> = O & Obj<{[K in Name]: Param }>;
type SwitchObj<Param extends string, Name extends string, O extends Obj<any>> = SafeObj<O, Name, Param>[Param];
type Not<T extends string> = SwitchObj<T, 'InvalidNotParam', {
  '1': '0';
  '0': '1';
}>;
type UnionHas<Union extends string, K extends string> = ({[S in Union]: '1' } & { [k: string]: '0' })[K];
type Obj2Keys<T> = {[K in keyof T]: K } & { [k: string]: undefined };

// data...
type Item1 = { a: string, b: number, c: boolean };

// okay, Omit, let's go.
type Omit_<T extends { [s: string]: any }, K extends keyof T> =
  {[P2 in keyof T]: { 1: Obj2Keys<T>[P2], 0: undefined }[Not<UnionHas<K, P2>>]}
type T1 = Omit_<Item1, "a">;
// intermediary result: { a: undefined; b: "b"; c: "c"; }
type T2 = {[P1 in T1[keyof Item1] ]: Item1[P1]}; // { b: number, c: boolean };
// ^ great, the result we want!
// now let's combine the steps?!
type Omit<T extends { [s: string]: any }, K extends keyof T> =
  {[P1 in {[P2 in keyof T]: { 1: Obj2Keys<T>[P2], 0: undefined }[Not<UnionHas<K, P2>>]}[keyof T] ]: T[P1]};
type T3 = Omit<Item1, "a">;
// ^ yields { a: string, b: number, c: boolean }, not { b: number, c: boolean }
// uh, could we instead do the next step in a separate wrapper type?:
type Omit2<T extends { [s: string]: any }, K extends keyof T> = Omit_<T, K>[keyof T];
// ^ not complete yet, but this is the minimum repro of the part that's going wrong
type T4 = Omit2<Item1, "a">;
// ^ nope, foiled again! 'a'|'b'|'c' instead of 'b'|'c'... wth? 
// fails unless this access step is done after the result is calculated, dunno why

Similar issue encountered in my attempt to calculate union differences to resolve #13470.

Expected behavior:
Operations can be combined so as to make more sophisticated types.

Actual behavior:
The compiler gets confused if the access step directly follows the previous half of the computation.

Edit: it appears #16018 is closer to a minimum repro of this same issue.

@KiaraGrouwstra
Copy link
Contributor Author

Fixed by @nirendy at #12215. 😃

@KiaraGrouwstra
Copy link
Contributor Author

Here's another occurrence that doesn't appears solved with those defaults:

export type Obj<T> = { [k: string]: T };
export type TupleHasIndex<Arr extends any[], I extends number> = ({[K in keyof Arr]: '1' } & Array<'0'>)[I];
// ^ #15768, TS2536 `X cannot be used to index Y` on generic
type ObjectHasKey<O extends {}, K extends string> =
    ({[K in keyof O]: '1' } & Obj<'0'>)[K];
type NumberToString = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50','51','52','53','54','55','56','57','58','59','60','61','62','63','64','65','66','67','68','69','70','71','72','73','74','75','76','77','78','79','80','81','82','83','84','85','86','87','88','89','90','91','92','93','94','95','96','97','98','99','100','101','102','103','104','105','106','107','108','109','110','111','112','113','114','115','116','117','118','119','120','121','122','123','124','125','126','127','128','129','130','131','132','133','134','135','136','137','138','139','140','141','142','143','144','145','146','147','148','149','150','151','152','153','154','155','156','157','158','159','160','161','162','163','164','165','166','167','168','169','170','171','172','173','174','175','176','177','178','179','180','181','182','183','184','185','186','187','188','189','190','191','192','193','194','195','196','197','198','199','200','201','202','203','204','205','206','207','208','209','210','211','212','213','214','215','216','217','218','219','220','221','222','223','224','225','226','227','228','229','230','231','232','233','234','235','236','237','238','239','240','241','242','243','244','245','246','247','248','249','250','251','252','253','254','255'];
type Inc = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256];
type Overwrite<K, T> = {[P in keyof T | keyof K]: { 1: T[P], 0: K[P] }[ObjectHasKey<T, P>]};

type TupleToObject<R extends any[], I extends number = 0, Acc = {}> =
    { 1: TupleToObject<R, Inc[I], Overwrite<Acc, { [P in NumberToString[I]]: R[I] }>>, 0: Acc }[TupleHasIndex<R, I>];

type TestArr = ['a', 'b', 'c'];
type Arr2ObjTest = TupleToObject<TestArr>; // { 0: "a"; 1: "b"; 2: "c"; }
type keys = keyof Arr2ObjTest // "0" | "1" | "2"

// type TupleIndicesToUnion<R extends any[]> = keyof TupleToObject<R>;
type TupleIndicesToUnion<R extends any[], O extends TupleToObject<R, 0> = TupleToObject<R, 0>> = keyof O;
// ^ split into steps using defaults following @niirendy in #12215, same result
type ArrKeys2UnionTest = TupleIndicesToUnion<TestArr>;
// ^ expected to equal `keys`, but gives `never` (O yield `{}`)

@KiaraGrouwstra
Copy link
Contributor Author

Worked around this one by typing the last one differently altogether, making the root cause less urgent again. I'll re-close until a new blocker comes in I guess.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant