|
| 1 | +// @target: es5 |
| 2 | +let o = { a: 1, b: 'no' } |
| 3 | +let o2 = { b: 'yes', c: true } |
| 4 | +let swap = { a: 'yes', b: -1 }; |
| 5 | + |
| 6 | +let addAfter: { a: number, b: string, c: boolean } = |
| 7 | + { ...o, c: false } |
| 8 | +let addBefore: { a: number, b: string, c: boolean } = |
| 9 | + { c: false, ...o } |
| 10 | +// Note: ignore still changes the order that properties are printed |
| 11 | +let ignore: { a: number, b: string } = |
| 12 | + { b: 'ignored', ...o } |
| 13 | +let override: { a: number, b: string } = |
| 14 | + { ...o, b: 'override' } |
| 15 | +let nested: { a: number, b: boolean, c: string } = |
| 16 | + { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } |
| 17 | +let combined: { a: number, b: string, c: boolean } = |
| 18 | + { ...o, ...o2 } |
| 19 | +let combinedBefore: { a: number, b: string, c: boolean } = |
| 20 | + { b: 'ok', ...o, ...o2 } |
| 21 | +let combinedMid: { a: number, b: string, c: boolean } = |
| 22 | + { ...o, b: 'ok', ...o2 } |
| 23 | +let combinedAfter: { a: number, b: string, c: boolean } = |
| 24 | + { ...o, ...o2, b: 'ok' } |
| 25 | +let combinedNested: { a: number, b: boolean, c: string, d: string } = |
| 26 | + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } |
| 27 | +let combinedNestedChangeType: { a: number, b: boolean, c: number } = |
| 28 | + { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } |
| 29 | +let propertyNested: { a: { a: number, b: string } } = |
| 30 | + { a: { ... o } } |
| 31 | +// accessors don't copy the descriptor |
| 32 | +// (which means that readonly getters become read/write properties) |
| 33 | +let op = { get a () { return 6 } }; |
| 34 | +let getter: { a: number, c: number } = |
| 35 | + { ...op, c: 7 } |
| 36 | +getter.a = 12; |
| 37 | + |
| 38 | +// null and undefined are just skipped |
| 39 | +let spreadNull: { a: number } = |
| 40 | + { a: 7, ...null } |
| 41 | +let spreadUndefined: { a: number } = |
| 42 | + { a: 7, ...undefined } |
| 43 | + |
| 44 | +// methods are not enumerable |
| 45 | +class C { p = 1; m() { } } |
| 46 | +let c: C = new C() |
| 47 | +let spreadC: { p: number } = { ...c } |
| 48 | + |
| 49 | +// own methods are enumerable |
| 50 | +let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; |
| 51 | +cplus.plus(); |
| 52 | + |
| 53 | +// new field's type conflicting with existing field is OK |
| 54 | +let changeTypeAfter: { a: string, b: string } = |
| 55 | + { ...o, a: 'wrong type?' } |
| 56 | +let changeTypeBefore: { a: number, b: string } = |
| 57 | + { a: 'wrong type?', ...o }; |
| 58 | +let changeTypeBoth: { a: string, b: number } = |
| 59 | + { ...o, ...swap }; |
| 60 | + |
| 61 | +// optional |
| 62 | +let definiteBoolean: { sn: boolean }; |
| 63 | +let definiteString: { sn: string }; |
| 64 | +let optionalString: { sn?: string }; |
| 65 | +let optionalNumber: { sn?: number }; |
| 66 | +let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; |
| 67 | +let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; |
| 68 | +let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; |
| 69 | + |
| 70 | +// computed property |
| 71 | +let computedFirst: { a: number, b: string, "before everything": number } = |
| 72 | + { ['before everything']: 12, ...o, b: 'yes' } |
| 73 | +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = |
| 74 | + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } |
| 75 | +let computedAfter: { a: number, b: string, "at the end": number } = |
| 76 | + { ...o, b: 'yeah', ['at the end']: 14 } |
| 77 | +// shortcut syntax |
| 78 | +let a = 12; |
| 79 | +let shortCutted: { a: number, b: string } = { ...o, a } |
| 80 | + |
| 81 | +// generics |
| 82 | +function f<T, U>(t: T, u: U): { id: string, ...T, ...U } { |
| 83 | + return { id: 'id', ...t, ...u }; |
| 84 | +} |
| 85 | +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = |
| 86 | + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) |
| 87 | +let overlap: { id: string, a: number, b: string } = |
| 88 | + f({ a: 1 }, { a: 2, b: 'extra' }) |
| 89 | +let overlapConflict: { id:string, a: string } = |
| 90 | + f({ a: 1 }, { a: 'mismatch' }) |
| 91 | +let overwriteId: { id: boolean, a: number, c: number, d: string } = |
| 92 | + f({ a: 1, id: true }, { c: 1, d: 'no' }) |
| 93 | + |
| 94 | +class D { m() { }; q = 2; } |
| 95 | +let classesAreWrong: { id: string, ...C, ...D } = |
| 96 | + f(new C(), new D()) |
0 commit comments