6aeb8c12cc
* Create separate types for equivalent aliased unions * Accept new baselines * Preserve original types for union types * Accept new baselines * Preserve intersection origin for union types * Accept new baselines * Accept new baselines * Preserve aliases during relationship checks * Accept new baselines * Preserve aliases for intersection and indexed access types * Accept new baselines * Compute intersection-of-unions cross product without recursion * Accept new baselines * Use denormalized type objects for origin / support 'keyof' origins * Accept new baselines * Fix fourslash test * Recursively extract named union types * Accept new baselines * Map on union origin in mapType to better preserve aliases and origins * Remove redundant call * Accept new baselines * Revert back to declared type when branches produce equivalent union * Accept new baselines * Don't include denormal origin types in regular type statistics * Fix issue with unions not being marked primitive-only * Allow new alias to be associated with type alias instantiation * Accept new baselines * Revert "Accept new baselines" This reverts commit4507270cc1
. * Revert "Allow new alias to be associated with type alias instantiation" This reverts commit2c2d06dfe1
.
543 lines
14 KiB
Plaintext
543 lines
14 KiB
Plaintext
=== tests/cases/conformance/expressions/typeAssertions/constAssertions.ts ===
|
|
let v1 = 'abc' as const;
|
|
>v1 : "abc"
|
|
>'abc' as const : "abc"
|
|
>'abc' : "abc"
|
|
|
|
let v2 = `abc` as const;
|
|
>v2 : "abc"
|
|
>`abc` as const : "abc"
|
|
>`abc` : "abc"
|
|
|
|
let v3 = 10 as const;
|
|
>v3 : 10
|
|
>10 as const : 10
|
|
>10 : 10
|
|
|
|
let v4 = -10 as const;
|
|
>v4 : -10
|
|
>-10 as const : -10
|
|
>-10 : -10
|
|
>10 : 10
|
|
|
|
let v5 = +10 as const;
|
|
>v5 : 10
|
|
>+10 as const : 10
|
|
>+10 : 10
|
|
>10 : 10
|
|
|
|
let v6 = 10n as const;
|
|
>v6 : 10n
|
|
>10n as const : 10n
|
|
>10n : 10n
|
|
|
|
let v7 = -10n as const;
|
|
>v7 : -10n
|
|
>-10n as const : -10n
|
|
>-10n : -10n
|
|
>10n : 10n
|
|
|
|
let v8 = true as const;
|
|
>v8 : true
|
|
>true as const : true
|
|
>true : true
|
|
|
|
let v9 = false as const;
|
|
>v9 : false
|
|
>false as const : false
|
|
>false : false
|
|
|
|
let c1 = 'abc' as const;
|
|
>c1 : "abc"
|
|
>'abc' as const : "abc"
|
|
>'abc' : "abc"
|
|
|
|
let c2 = `abc` as const;
|
|
>c2 : "abc"
|
|
>`abc` as const : "abc"
|
|
>`abc` : "abc"
|
|
|
|
let c3 = 10 as const;
|
|
>c3 : 10
|
|
>10 as const : 10
|
|
>10 : 10
|
|
|
|
let c4 = -10 as const;
|
|
>c4 : -10
|
|
>-10 as const : -10
|
|
>-10 : -10
|
|
>10 : 10
|
|
|
|
let c5 = +10 as const;
|
|
>c5 : 10
|
|
>+10 as const : 10
|
|
>+10 : 10
|
|
>10 : 10
|
|
|
|
let c6 = 10n as const;
|
|
>c6 : 10n
|
|
>10n as const : 10n
|
|
>10n : 10n
|
|
|
|
let c7 = -10n as const;
|
|
>c7 : -10n
|
|
>-10n as const : -10n
|
|
>-10n : -10n
|
|
>10n : 10n
|
|
|
|
let c8 = true as const;
|
|
>c8 : true
|
|
>true as const : true
|
|
>true : true
|
|
|
|
let c9 = false as const;
|
|
>c9 : false
|
|
>false as const : false
|
|
>false : false
|
|
|
|
let vv1 = v1;
|
|
>vv1 : "abc"
|
|
>v1 : "abc"
|
|
|
|
let vc1 = c1;
|
|
>vc1 : "abc"
|
|
>c1 : "abc"
|
|
|
|
let a1 = [] as const;
|
|
>a1 : readonly []
|
|
>[] as const : readonly []
|
|
>[] : readonly []
|
|
|
|
let a2 = [1, 2, 3] as const;
|
|
>a2 : readonly [1, 2, 3]
|
|
>[1, 2, 3] as const : readonly [1, 2, 3]
|
|
>[1, 2, 3] : readonly [1, 2, 3]
|
|
>1 : 1
|
|
>2 : 2
|
|
>3 : 3
|
|
|
|
let a3 = [10, 'hello', true] as const;
|
|
>a3 : readonly [10, "hello", true]
|
|
>[10, 'hello', true] as const : readonly [10, "hello", true]
|
|
>[10, 'hello', true] : readonly [10, "hello", true]
|
|
>10 : 10
|
|
>'hello' : "hello"
|
|
>true : true
|
|
|
|
let a4 = [...[1, 2, 3]] as const;
|
|
>a4 : readonly [1, 2, 3]
|
|
>[...[1, 2, 3]] as const : readonly [1, 2, 3]
|
|
>[...[1, 2, 3]] : readonly [1, 2, 3]
|
|
>...[1, 2, 3] : 1 | 2 | 3
|
|
>[1, 2, 3] : readonly [1, 2, 3]
|
|
>1 : 1
|
|
>2 : 2
|
|
>3 : 3
|
|
|
|
let a5 = [1, 2, 3];
|
|
>a5 : number[]
|
|
>[1, 2, 3] : number[]
|
|
>1 : 1
|
|
>2 : 2
|
|
>3 : 3
|
|
|
|
let a6 = [...a5] as const;
|
|
>a6 : readonly number[]
|
|
>[...a5] as const : readonly number[]
|
|
>[...a5] : readonly number[]
|
|
>...a5 : number
|
|
>a5 : number[]
|
|
|
|
let a7 = [...a6];
|
|
>a7 : number[]
|
|
>[...a6] : number[]
|
|
>...a6 : number
|
|
>a6 : readonly number[]
|
|
|
|
let a8 = ['abc', ...a7] as const;
|
|
>a8 : readonly ["abc", ...number[]]
|
|
>['abc', ...a7] as const : readonly ["abc", ...number[]]
|
|
>['abc', ...a7] : readonly ["abc", ...number[]]
|
|
>'abc' : "abc"
|
|
>...a7 : number
|
|
>a7 : number[]
|
|
|
|
let a9 = [...a8];
|
|
>a9 : (number | "abc")[]
|
|
>[...a8] : (number | "abc")[]
|
|
>...a8 : number | "abc"
|
|
>a8 : readonly ["abc", ...number[]]
|
|
|
|
declare let d: { [x: string]: string };
|
|
>d : { [x: string]: string; }
|
|
>x : string
|
|
|
|
let o1 = { x: 10, y: 20 } as const;
|
|
>o1 : { readonly x: 10; readonly y: 20; }
|
|
>{ x: 10, y: 20 } as const : { readonly x: 10; readonly y: 20; }
|
|
>{ x: 10, y: 20 } : { readonly x: 10; readonly y: 20; }
|
|
>x : 10
|
|
>10 : 10
|
|
>y : 20
|
|
>20 : 20
|
|
|
|
let o2 = { a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const;
|
|
>o2 : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; }
|
|
>{ a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; }
|
|
>{ a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; }
|
|
>a : 1
|
|
>1 : 1
|
|
>'b' : 2
|
|
>2 : 2
|
|
>['c'] : 3
|
|
>'c' : "c"
|
|
>3 : 3
|
|
>d : () => void
|
|
>['e' + ''] : 4
|
|
>'e' + '' : string
|
|
>'e' : "e"
|
|
>'' : ""
|
|
>4 : 4
|
|
|
|
let o3 = { ...o1, ...o2 } as const;
|
|
>o3 : { readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; readonly x: 10; readonly y: 20; }
|
|
>{ ...o1, ...o2 } as const : { readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; readonly x: 10; readonly y: 20; }
|
|
>{ ...o1, ...o2 } : { readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; readonly x: 10; readonly y: 20; }
|
|
>o1 : { readonly x: 10; readonly y: 20; }
|
|
>o2 : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly b: 2; readonly c: 3; readonly d: () => void; }
|
|
|
|
let o4 = { a: 1, b: 2 };
|
|
>o4 : { a: number; b: number; }
|
|
>{ a: 1, b: 2 } : { a: number; b: number; }
|
|
>a : number
|
|
>1 : 1
|
|
>b : number
|
|
>2 : 2
|
|
|
|
let o5 = { ...o4 } as const;
|
|
>o5 : { readonly a: number; readonly b: number; }
|
|
>{ ...o4 } as const : { readonly a: number; readonly b: number; }
|
|
>{ ...o4 } : { readonly a: number; readonly b: number; }
|
|
>o4 : { a: number; b: number; }
|
|
|
|
let o6 = { ...o5 };
|
|
>o6 : { a: number; b: number; }
|
|
>{ ...o5 } : { a: number; b: number; }
|
|
>o5 : { readonly a: number; readonly b: number; }
|
|
|
|
let o7 = { ...d } as const;
|
|
>o7 : { readonly [x: string]: string; }
|
|
>{ ...d } as const : { readonly [x: string]: string; }
|
|
>{ ...d } : { readonly [x: string]: string; }
|
|
>d : { [x: string]: string; }
|
|
|
|
let o8 = { ...o7 };
|
|
>o8 : { [x: string]: string; }
|
|
>{ ...o7 } : { [x: string]: string; }
|
|
>o7 : { readonly [x: string]: string; }
|
|
|
|
let o9 = { x: 10, foo() { this.x = 20 } } as const; // Error
|
|
>o9 : { readonly x: 10; readonly foo: () => void; }
|
|
>{ x: 10, foo() { this.x = 20 } } as const : { readonly x: 10; readonly foo: () => void; }
|
|
>{ x: 10, foo() { this.x = 20 } } : { readonly x: 10; readonly foo: () => void; }
|
|
>x : 10
|
|
>10 : 10
|
|
>foo : () => void
|
|
>this.x = 20 : 20
|
|
>this.x : any
|
|
>this : { readonly x: 10; readonly foo: () => void; }
|
|
>x : any
|
|
>20 : 20
|
|
|
|
let p1 = (10) as const;
|
|
>p1 : 10
|
|
>(10) as const : 10
|
|
>(10) : 10
|
|
>10 : 10
|
|
|
|
let p2 = ((-10)) as const;
|
|
>p2 : -10
|
|
>((-10)) as const : -10
|
|
>((-10)) : -10
|
|
>(-10) : -10
|
|
>-10 : -10
|
|
>10 : 10
|
|
|
|
let p3 = ([(10)]) as const;
|
|
>p3 : readonly [10]
|
|
>([(10)]) as const : readonly [10]
|
|
>([(10)]) : readonly [10]
|
|
>[(10)] : readonly [10]
|
|
>(10) : 10
|
|
>10 : 10
|
|
|
|
let p4 = [[[[10]]]] as const;
|
|
>p4 : readonly [readonly [readonly [readonly [10]]]]
|
|
>[[[[10]]]] as const : readonly [readonly [readonly [readonly [10]]]]
|
|
>[[[[10]]]] : readonly [readonly [readonly [readonly [10]]]]
|
|
>[[[10]]] : readonly [readonly [readonly [10]]]
|
|
>[[10]] : readonly [readonly [10]]
|
|
>[10] : readonly [10]
|
|
>10 : 10
|
|
|
|
let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } } as const;
|
|
>x1 : { readonly x: 10; readonly y: readonly [20, 30]; readonly z: { readonly a: { readonly b: 42; }; }; }
|
|
>{ x: 10, y: [20, 30], z: { a: { b: 42 } } } as const : { readonly x: 10; readonly y: readonly [20, 30]; readonly z: { readonly a: { readonly b: 42; }; }; }
|
|
>{ x: 10, y: [20, 30], z: { a: { b: 42 } } } : { readonly x: 10; readonly y: readonly [20, 30]; readonly z: { readonly a: { readonly b: 42; }; }; }
|
|
>x : 10
|
|
>10 : 10
|
|
>y : readonly [20, 30]
|
|
>[20, 30] : readonly [20, 30]
|
|
>20 : 20
|
|
>30 : 30
|
|
>z : { readonly a: { readonly b: 42; }; }
|
|
>{ a: { b: 42 } } : { readonly a: { readonly b: 42; }; }
|
|
>a : { readonly b: 42; }
|
|
>{ b: 42 } : { readonly b: 42; }
|
|
>b : 42
|
|
>42 : 42
|
|
|
|
let q1 = <const> 10;
|
|
>q1 : 10
|
|
><const> 10 : 10
|
|
>10 : 10
|
|
|
|
let q2 = <const> 'abc';
|
|
>q2 : "abc"
|
|
><const> 'abc' : "abc"
|
|
>'abc' : "abc"
|
|
|
|
let q3 = <const> true;
|
|
>q3 : true
|
|
><const> true : true
|
|
>true : true
|
|
|
|
let q4 = <const> [1, 2, 3];
|
|
>q4 : readonly [1, 2, 3]
|
|
><const> [1, 2, 3] : readonly [1, 2, 3]
|
|
>[1, 2, 3] : readonly [1, 2, 3]
|
|
>1 : 1
|
|
>2 : 2
|
|
>3 : 3
|
|
|
|
let q5 = <const> { x: 10, y: 20 };
|
|
>q5 : { readonly x: 10; readonly y: 20; }
|
|
><const> { x: 10, y: 20 } : { readonly x: 10; readonly y: 20; }
|
|
>{ x: 10, y: 20 } : { readonly x: 10; readonly y: 20; }
|
|
>x : 10
|
|
>10 : 10
|
|
>y : 20
|
|
>20 : 20
|
|
|
|
declare function id<T>(x: T): T;
|
|
>id : <T>(x: T) => T
|
|
>x : T
|
|
|
|
let e1 = v1 as const; // Error
|
|
>e1 : "abc"
|
|
>v1 as const : "abc"
|
|
>v1 : "abc"
|
|
|
|
let e2 = (true ? 1 : 0) as const; // Error
|
|
>e2 : 0 | 1
|
|
>(true ? 1 : 0) as const : 0 | 1
|
|
>(true ? 1 : 0) : 0 | 1
|
|
>true ? 1 : 0 : 0 | 1
|
|
>true : true
|
|
>1 : 1
|
|
>0 : 0
|
|
|
|
let e3 = id(1) as const; // Error
|
|
>e3 : 1
|
|
>id(1) as const : 1
|
|
>id(1) : 1
|
|
>id : <T>(x: T) => T
|
|
>1 : 1
|
|
|
|
let t1 = 'foo' as const;
|
|
>t1 : "foo"
|
|
>'foo' as const : "foo"
|
|
>'foo' : "foo"
|
|
|
|
let t2 = 'bar' as const;
|
|
>t2 : "bar"
|
|
>'bar' as const : "bar"
|
|
>'bar' : "bar"
|
|
|
|
let t3 = `${t1}-${t2}` as const;
|
|
>t3 : "foo-bar"
|
|
>`${t1}-${t2}` as const : "foo-bar"
|
|
>`${t1}-${t2}` : "foo-bar"
|
|
>t1 : "foo"
|
|
>t2 : "bar"
|
|
|
|
let t4 = `${`(${t1})`}-${`(${t2})`}` as const;
|
|
>t4 : "(foo)-(bar)"
|
|
>`${`(${t1})`}-${`(${t2})`}` as const : "(foo)-(bar)"
|
|
>`${`(${t1})`}-${`(${t2})`}` : "(foo)-(bar)"
|
|
>`(${t1})` : "(foo)"
|
|
>t1 : "foo"
|
|
>`(${t2})` : "(bar)"
|
|
>t2 : "bar"
|
|
|
|
function ff1(x: 'foo' | 'bar', y: 1 | 2) {
|
|
>ff1 : (x: 'foo' | 'bar', y: 1 | 2) => "foo-1" | "foo-2" | "bar-1" | "bar-2"
|
|
>x : "foo" | "bar"
|
|
>y : 1 | 2
|
|
|
|
return `${x}-${y}` as const;
|
|
>`${x}-${y}` as const : "foo-1" | "foo-2" | "bar-1" | "bar-2"
|
|
>`${x}-${y}` : "foo-1" | "foo-2" | "bar-1" | "bar-2"
|
|
>x : "foo" | "bar"
|
|
>y : 1 | 2
|
|
}
|
|
|
|
function ff2<T extends string, U extends string>(x: T, y: U) {
|
|
>ff2 : <T extends string, U extends string>(x: T, y: U) => `${T}-${U}`
|
|
>x : T
|
|
>y : U
|
|
|
|
return `${x}-${y}` as const;
|
|
>`${x}-${y}` as const : `${T}-${U}`
|
|
>`${x}-${y}` : `${T}-${U}`
|
|
>x : T
|
|
>y : U
|
|
}
|
|
|
|
const ts1 = ff2('foo', 'bar');
|
|
>ts1 : "foo-bar"
|
|
>ff2('foo', 'bar') : "foo-bar"
|
|
>ff2 : <T extends string, U extends string>(x: T, y: U) => `${T}-${U}`
|
|
>'foo' : "foo"
|
|
>'bar' : "bar"
|
|
|
|
const ts2 = ff2('foo', !!true ? '0' : '1');
|
|
>ts2 : "foo-1" | "foo-0"
|
|
>ff2('foo', !!true ? '0' : '1') : "foo-1" | "foo-0"
|
|
>ff2 : <T extends string, U extends string>(x: T, y: U) => `${T}-${U}`
|
|
>'foo' : "foo"
|
|
>!!true ? '0' : '1' : "0" | "1"
|
|
>!!true : true
|
|
>!true : false
|
|
>true : true
|
|
>'0' : "0"
|
|
>'1' : "1"
|
|
|
|
const ts3 = ff2(!!true ? 'top' : 'bottom', !!true ? 'left' : 'right');
|
|
>ts3 : "top-left" | "top-right" | "bottom-left" | "bottom-right"
|
|
>ff2(!!true ? 'top' : 'bottom', !!true ? 'left' : 'right') : "top-left" | "top-right" | "bottom-left" | "bottom-right"
|
|
>ff2 : <T extends string, U extends string>(x: T, y: U) => `${T}-${U}`
|
|
>!!true ? 'top' : 'bottom' : "top" | "bottom"
|
|
>!!true : true
|
|
>!true : false
|
|
>true : true
|
|
>'top' : "top"
|
|
>'bottom' : "bottom"
|
|
>!!true ? 'left' : 'right' : "left" | "right"
|
|
>!!true : true
|
|
>!true : false
|
|
>true : true
|
|
>'left' : "left"
|
|
>'right' : "right"
|
|
|
|
function ff3(x: 'foo' | 'bar', y: object) {
|
|
>ff3 : (x: 'foo' | 'bar', y: object) => `foo${string}` | `bar${string}`
|
|
>x : "foo" | "bar"
|
|
>y : object
|
|
|
|
return `${x}${y}` as const;
|
|
>`${x}${y}` as const : `foo${string}` | `bar${string}`
|
|
>`${x}${y}` : `foo${string}` | `bar${string}`
|
|
>x : "foo" | "bar"
|
|
>y : object
|
|
}
|
|
|
|
type Action = "verify" | "write";
|
|
>Action : Action
|
|
|
|
type ContentMatch = "match" | "nonMatch";
|
|
>ContentMatch : ContentMatch
|
|
|
|
type Outcome = `${Action}_${ContentMatch}`;
|
|
>Outcome : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
|
|
function ff4(verify: boolean, contentMatches: boolean) {
|
|
>ff4 : (verify: boolean, contentMatches: boolean) => "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>verify : boolean
|
|
>contentMatches : boolean
|
|
|
|
const action : Action = verify ? `verify` : `write`;
|
|
>action : Action
|
|
>verify ? `verify` : `write` : "verify" | "write"
|
|
>verify : boolean
|
|
>`verify` : "verify"
|
|
>`write` : "write"
|
|
|
|
const contentMatch: ContentMatch = contentMatches ? `match` : `nonMatch`;
|
|
>contentMatch : ContentMatch
|
|
>contentMatches ? `match` : `nonMatch` : "match" | "nonMatch"
|
|
>contentMatches : boolean
|
|
>`match` : "match"
|
|
>`nonMatch` : "nonMatch"
|
|
|
|
const outcome: Outcome = `${action}_${contentMatch}` as const;
|
|
>outcome : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>`${action}_${contentMatch}` as const : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>`${action}_${contentMatch}` : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>action : Action
|
|
>contentMatch : ContentMatch
|
|
|
|
return outcome;
|
|
>outcome : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
}
|
|
|
|
function ff5(verify: boolean, contentMatches: boolean) {
|
|
>ff5 : (verify: boolean, contentMatches: boolean) => "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>verify : boolean
|
|
>contentMatches : boolean
|
|
|
|
const action = verify ? `verify` : `write`;
|
|
>action : "verify" | "write"
|
|
>verify ? `verify` : `write` : "verify" | "write"
|
|
>verify : boolean
|
|
>`verify` : "verify"
|
|
>`write` : "write"
|
|
|
|
const contentMatch = contentMatches ? `match` : `nonMatch`;
|
|
>contentMatch : "match" | "nonMatch"
|
|
>contentMatches ? `match` : `nonMatch` : "match" | "nonMatch"
|
|
>contentMatches : boolean
|
|
>`match` : "match"
|
|
>`nonMatch` : "nonMatch"
|
|
|
|
const outcome = `${action}_${contentMatch}` as const;
|
|
>outcome : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>`${action}_${contentMatch}` as const : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>`${action}_${contentMatch}` : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
>action : "verify" | "write"
|
|
>contentMatch : "match" | "nonMatch"
|
|
|
|
return outcome;
|
|
>outcome : "verify_match" | "verify_nonMatch" | "write_match" | "write_nonMatch"
|
|
}
|
|
|
|
function accessorNames<S extends string>(propName: S) {
|
|
>accessorNames : <S extends string>(propName: S) => readonly [`get-${S}`, `set-${S}`]
|
|
>propName : S
|
|
|
|
return [`get-${propName}`, `set-${propName}`] as const;
|
|
>[`get-${propName}`, `set-${propName}`] as const : readonly [`get-${S}`, `set-${S}`]
|
|
>[`get-${propName}`, `set-${propName}`] : readonly [`get-${S}`, `set-${S}`]
|
|
>`get-${propName}` : `get-${S}`
|
|
>propName : S
|
|
>`set-${propName}` : `set-${S}`
|
|
>propName : S
|
|
}
|
|
|
|
const ns1 = accessorNames('foo');
|
|
>ns1 : readonly ["get-foo", "set-foo"]
|
|
>accessorNames('foo') : readonly ["get-foo", "set-foo"]
|
|
>accessorNames : <S extends string>(propName: S) => readonly [`get-${S}`, `set-${S}`]
|
|
>'foo' : "foo"
|
|
|