|
| 1 | +tests/cases/conformance/types/mapped/mappedTypeAsClauses.ts(130,3): error TS2345: Argument of type '"a"' is not assignable to parameter of type '"b"'. |
| 2 | + |
| 3 | + |
| 4 | +==== tests/cases/conformance/types/mapped/mappedTypeAsClauses.ts (1 errors) ==== |
| 5 | + // Mapped type 'as N' clauses |
| 6 | + |
| 7 | + type Getters<T> = { [P in keyof T & string as `get${Capitalize<P>}`]: () => T[P] }; |
| 8 | + type TG1 = Getters<{ foo: string, bar: number, baz: { z: boolean } }>; |
| 9 | + |
| 10 | + // Mapped type with 'as N' clause has no constraint on 'in T' clause |
| 11 | + |
| 12 | + type PropDef<K extends keyof any, T> = { name: K, type: T }; |
| 13 | + |
| 14 | + type TypeFromDefs<T extends PropDef<keyof any, any>> = { [P in T as P['name']]: P['type'] }; |
| 15 | + |
| 16 | + type TP1 = TypeFromDefs<{ name: 'a', type: string } | { name: 'b', type: number } | { name: 'a', type: boolean }>; |
| 17 | + |
| 18 | + // No array or tuple type mapping when 'as N' clause present |
| 19 | + |
| 20 | + type TA1 = Getters<string[]>; |
| 21 | + type TA2 = Getters<[number, boolean]>; |
| 22 | + |
| 23 | + // Filtering using 'as N' clause |
| 24 | + |
| 25 | + type Methods<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] }; |
| 26 | + type TM1 = Methods<{ foo(): number, bar(x: string): boolean, baz: string | number }>; |
| 27 | + |
| 28 | + // Mapping to multiple names using 'as N' clause |
| 29 | + |
| 30 | + type DoubleProp<T> = { [P in keyof T & string as `${P}1` | `${P}2`]: T[P] } |
| 31 | + type TD1 = DoubleProp<{ a: string, b: number }>; // { a1: string, a2: string, b1: number, b2: number } |
| 32 | + type TD2 = keyof TD1; // 'a1' | 'a2' | 'b1' | 'b2' |
| 33 | + type TD3<U> = keyof DoubleProp<U>; // `${keyof U & string}1` | `${keyof U & string}2` |
| 34 | + |
| 35 | + // Repro from #40619 |
| 36 | + |
| 37 | + type Lazyify<T> = { |
| 38 | + [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K] |
| 39 | + }; |
| 40 | + |
| 41 | + interface Person { |
| 42 | + readonly name: string; |
| 43 | + age: number; |
| 44 | + location?: string; |
| 45 | + } |
| 46 | + |
| 47 | + type LazyPerson = Lazyify<Person>; |
| 48 | + |
| 49 | + // Repro from #40833 |
| 50 | + |
| 51 | + type Example = {foo: string, bar: number}; |
| 52 | + |
| 53 | + type PickByValueType<T, U> = { |
| 54 | + [K in keyof T as T[K] extends U ? K : never]: T[K] |
| 55 | + }; |
| 56 | + |
| 57 | + type T1 = PickByValueType<Example, string>; |
| 58 | + const e1: T1 = { |
| 59 | + foo: "hello" |
| 60 | + }; |
| 61 | + type T2 = keyof T1; |
| 62 | + const e2: T2 = "foo"; |
| 63 | + |
| 64 | + // Repro from #41133 |
| 65 | + |
| 66 | + interface Car { |
| 67 | + name: string; |
| 68 | + seats: number; |
| 69 | + engine: Engine; |
| 70 | + wheels: Wheel[]; |
| 71 | + } |
| 72 | + |
| 73 | + interface Engine { |
| 74 | + manufacturer: string; |
| 75 | + horsepower: number; |
| 76 | + } |
| 77 | + |
| 78 | + interface Wheel { |
| 79 | + type: "summer" | "winter"; |
| 80 | + radius: number; |
| 81 | + } |
| 82 | + |
| 83 | + type Primitive = string | number | boolean; |
| 84 | + type OnlyPrimitives<T> = { [K in keyof T as T[K] extends Primitive ? K : never]: T[K] }; |
| 85 | + |
| 86 | + let primitiveCar: OnlyPrimitives<Car>; // { name: string; seats: number; } |
| 87 | + let keys: keyof OnlyPrimitives<Car>; // "name" | "seats" |
| 88 | + |
| 89 | + type KeysOfPrimitives<T> = keyof OnlyPrimitives<T>; |
| 90 | + |
| 91 | + let carKeys: KeysOfPrimitives<Car>; // "name" | "seats" |
| 92 | + |
| 93 | + // Repro from #41453 |
| 94 | + |
| 95 | + type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false; |
| 96 | + |
| 97 | + type If<Cond extends boolean, Then, Else> = Cond extends true ? Then : Else; |
| 98 | + |
| 99 | + type GetKey<S, V> = keyof { [TP in keyof S as Equal<S[TP], V> extends true ? TP : never]: any }; |
| 100 | + |
| 101 | + type GetKeyWithIf<S, V> = keyof { [TP in keyof S as If<Equal<S[TP], V>, TP, never>]: any }; |
| 102 | + |
| 103 | + type GetObjWithIf<S, V> = { [TP in keyof S as If<Equal<S[TP], V>, TP, never>]: any }; |
| 104 | + |
| 105 | + type Task = { |
| 106 | + isDone: boolean; |
| 107 | + }; |
| 108 | + |
| 109 | + type Schema = { |
| 110 | + root: { |
| 111 | + title: string; |
| 112 | + task: Task; |
| 113 | + } |
| 114 | + Task: Task; |
| 115 | + }; |
| 116 | + |
| 117 | + type Res1 = GetKey<Schema, Schema['root']['task']>; // "Task" |
| 118 | + type Res2 = GetKeyWithIf<Schema, Schema['root']['task']>; // "Task" |
| 119 | + type Res3 = keyof GetObjWithIf<Schema, Schema['root']['task']>; // "Task" |
| 120 | + |
| 121 | + // Repro from #44019 |
| 122 | + |
| 123 | + type KeysExtendedBy<T, U> = keyof { [K in keyof T as U extends T[K] ? K : never] : T[K] }; |
| 124 | + |
| 125 | + interface M { |
| 126 | + a: boolean; |
| 127 | + b: number; |
| 128 | + } |
| 129 | + |
| 130 | + function f(x: KeysExtendedBy<M, number>) { |
| 131 | + return x; |
| 132 | + } |
| 133 | + |
| 134 | + f("a"); // Error, should allow only "b" |
| 135 | + ~~~ |
| 136 | +!!! error TS2345: Argument of type '"a"' is not assignable to parameter of type '"b"'. |
| 137 | + |
| 138 | + type NameMap = { 'a': 'x', 'b': 'y', 'c': 'z' }; |
| 139 | + |
| 140 | + // Distributive, will be simplified |
| 141 | + |
| 142 | + type TS0<T> = keyof { [P in keyof T as keyof Record<P, number>]: string }; |
| 143 | + type TS1<T> = keyof { [P in keyof T as Extract<P, 'a' | 'b' | 'c'>]: string }; |
| 144 | + type TS2<T> = keyof { [P in keyof T as P & ('a' | 'b' | 'c')]: string }; |
| 145 | + type TS3<T> = keyof { [P in keyof T as Exclude<P, 'a' | 'b' | 'c'>]: string }; |
| 146 | + type TS4<T> = keyof { [P in keyof T as NameMap[P & keyof NameMap]]: string }; |
| 147 | + type TS5<T> = keyof { [P in keyof T & keyof NameMap as NameMap[P]]: string }; |
| 148 | + type TS6<T, U, V> = keyof { [ K in keyof T as V & (K extends U ? K : never)]: string }; |
| 149 | + |
| 150 | + // Non-distributive, won't be simplified |
| 151 | + |
| 152 | + type TN0<T> = keyof { [P in keyof T as T[P] extends number ? P : never]: string }; |
| 153 | + type TN1<T> = keyof { [P in keyof T as number extends T[P] ? P : never]: string }; |
| 154 | + type TN2<T> = keyof { [P in keyof T as 'a' extends P ? 'x' : 'y']: string }; |
| 155 | + type TN3<T> = keyof { [P in keyof T as Exclude<Exclude<Exclude<P, 'c'>, 'b'>, 'a'>]: string }; |
| 156 | + type TN4<T, U> = keyof { [K in keyof T as (K extends U ? T[K] : never) extends T[K] ? K : never]: string }; |
| 157 | + type TN5<T, U> = keyof { [K in keyof T as keyof { [P in K as T[P] extends U ? K : never]: true }]: string }; |
| 158 | + |
0 commit comments