mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 04:43:37 -05:00
Merge pull request #28312 from Microsoft/genericRest
Generic object rest variables and parameters
This commit is contained in:
@@ -520,6 +520,8 @@ namespace ts {
|
||||
let deferredGlobalTemplateStringsArrayType: ObjectType;
|
||||
let deferredGlobalImportMetaType: ObjectType;
|
||||
let deferredGlobalExtractSymbol: Symbol;
|
||||
let deferredGlobalExcludeSymbol: Symbol;
|
||||
let deferredGlobalPickSymbol: Symbol;
|
||||
let deferredGlobalBigIntType: ObjectType;
|
||||
|
||||
const allPotentiallyUnusedIdentifiers = createMap<PotentiallyUnusedIdentifier[]>(); // key is file name
|
||||
@@ -4622,18 +4624,25 @@ namespace ts {
|
||||
if (source.flags & TypeFlags.Never) {
|
||||
return emptyObjectType;
|
||||
}
|
||||
|
||||
if (source.flags & TypeFlags.Union) {
|
||||
return mapType(source, t => getRestType(t, properties, symbol));
|
||||
}
|
||||
|
||||
const members = createSymbolTable();
|
||||
const names = createUnderscoreEscapedMap<true>();
|
||||
for (const name of properties) {
|
||||
names.set(getTextOfPropertyName(name), true);
|
||||
const omitKeyType = getUnionType(map(properties, getLiteralTypeFromPropertyName));
|
||||
if (isGenericObjectType(source) || isGenericIndexType(omitKeyType)) {
|
||||
if (omitKeyType.flags & TypeFlags.Never) {
|
||||
return source;
|
||||
}
|
||||
const pickTypeAlias = getGlobalPickSymbol();
|
||||
const excludeTypeAlias = getGlobalExcludeSymbol();
|
||||
if (!pickTypeAlias || !excludeTypeAlias) {
|
||||
return errorType;
|
||||
}
|
||||
const pickKeys = getTypeAliasInstantiation(excludeTypeAlias, [getIndexType(source), omitKeyType]);
|
||||
return getTypeAliasInstantiation(pickTypeAlias, [source, pickKeys]);
|
||||
}
|
||||
const members = createSymbolTable();
|
||||
for (const prop of getPropertiesOfType(source)) {
|
||||
if (!names.has(prop.escapedName)
|
||||
if (!isTypeAssignableTo(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), omitKeyType)
|
||||
&& !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))
|
||||
&& isSpreadableProperty(prop)) {
|
||||
members.set(prop.escapedName, getSpreadSymbol(prop));
|
||||
@@ -4669,7 +4678,7 @@ namespace ts {
|
||||
let type: Type | undefined;
|
||||
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
|
||||
if (declaration.dotDotDotToken) {
|
||||
if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType) || isGenericObjectType(parentType)) {
|
||||
if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) {
|
||||
error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
|
||||
return errorType;
|
||||
}
|
||||
@@ -4684,12 +4693,8 @@ namespace ts {
|
||||
else {
|
||||
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
|
||||
const name = declaration.propertyName || <Identifier>declaration.name;
|
||||
const exprType = isComputedPropertyName(name)
|
||||
? checkComputedPropertyName(name)
|
||||
: isIdentifier(name)
|
||||
? getLiteralType(unescapeLeadingUnderscores(name.escapedText))
|
||||
: checkExpression(name);
|
||||
const declaredType = checkIndexedAccessIndexType(getIndexedAccessType(getApparentType(parentType), exprType, name), name);
|
||||
const exprType = getLiteralTypeFromPropertyName(name);
|
||||
const declaredType = checkIndexedAccessIndexType(getIndexedAccessType(parentType, exprType, name), name);
|
||||
type = getFlowTypeOfReference(declaration, getConstraintForLocation(declaredType, declaration.name));
|
||||
}
|
||||
}
|
||||
@@ -6825,7 +6830,7 @@ namespace ts {
|
||||
if (isMappedTypeWithKeyofConstraintDeclaration(type)) {
|
||||
// We have a { [P in keyof T]: X }
|
||||
for (const prop of getPropertiesOfType(modifiersType)) {
|
||||
addMemberForKeyType(getLiteralTypeFromPropertyName(prop, include));
|
||||
addMemberForKeyType(getLiteralTypeFromProperty(prop, include));
|
||||
}
|
||||
if (modifiersType.flags & TypeFlags.Any || getIndexInfoOfType(modifiersType, IndexKind.String)) {
|
||||
addMemberForKeyType(stringType);
|
||||
@@ -8677,6 +8682,14 @@ namespace ts {
|
||||
return deferredGlobalExtractSymbol || (deferredGlobalExtractSymbol = getGlobalSymbol("Extract" as __String, SymbolFlags.TypeAlias, Diagnostics.Cannot_find_global_type_0)!); // TODO: GH#18217
|
||||
}
|
||||
|
||||
function getGlobalExcludeSymbol(): Symbol {
|
||||
return deferredGlobalExcludeSymbol || (deferredGlobalExcludeSymbol = getGlobalSymbol("Exclude" as __String, SymbolFlags.TypeAlias, Diagnostics.Cannot_find_global_type_0)!); // TODO: GH#18217
|
||||
}
|
||||
|
||||
function getGlobalPickSymbol(): Symbol {
|
||||
return deferredGlobalPickSymbol || (deferredGlobalPickSymbol = getGlobalSymbol("Pick" as __String, SymbolFlags.TypeAlias, Diagnostics.Cannot_find_global_type_0)!); // TODO: GH#18217
|
||||
}
|
||||
|
||||
function getGlobalBigIntType(reportErrors: boolean) {
|
||||
return deferredGlobalBigIntType || (deferredGlobalBigIntType = getGlobalType("BigInt" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType;
|
||||
}
|
||||
@@ -9268,6 +9281,11 @@ namespace ts {
|
||||
type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false));
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyName(name: PropertyName) {
|
||||
return isIdentifier(name) ? getLiteralType(unescapeLeadingUnderscores(name.escapedText)) :
|
||||
getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name));
|
||||
}
|
||||
|
||||
function getBigIntLiteralType(node: BigIntLiteral): LiteralType {
|
||||
return getLiteralType({
|
||||
negative: false,
|
||||
@@ -9275,14 +9293,12 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) {
|
||||
function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags) {
|
||||
if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
|
||||
let type = getLateBoundSymbol(prop).nameType;
|
||||
if (!type && !isKnownSymbol(prop)) {
|
||||
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration);
|
||||
type = name && isNumericLiteral(name) ? getLiteralType(+name.text) :
|
||||
name && name.kind === SyntaxKind.ComputedPropertyName && isNumericLiteral(name.expression) ? getLiteralType(+name.expression.text) :
|
||||
getLiteralType(symbolName(prop));
|
||||
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration) as PropertyName;
|
||||
type = name && getLiteralTypeFromPropertyName(name) || getLiteralType(symbolName(prop));
|
||||
}
|
||||
if (type && type.flags & include) {
|
||||
return type;
|
||||
@@ -9291,8 +9307,8 @@ namespace ts {
|
||||
return neverType;
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyNames(type: Type, include: TypeFlags) {
|
||||
return getUnionType(map(getPropertiesOfType(type), t => getLiteralTypeFromPropertyName(t, include)));
|
||||
function getLiteralTypeFromProperties(type: Type, include: TypeFlags) {
|
||||
return getUnionType(map(getPropertiesOfType(type), t => getLiteralTypeFromProperty(t, include)));
|
||||
}
|
||||
|
||||
function getNonEnumNumberIndexInfo(type: Type) {
|
||||
@@ -9307,10 +9323,10 @@ namespace ts {
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
|
||||
type === wildcardType ? wildcardType :
|
||||
type.flags & TypeFlags.Any ? keyofConstraintType :
|
||||
stringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) :
|
||||
getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.UniqueESSymbol)]) :
|
||||
getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
|
||||
getLiteralTypeFromPropertyNames(type, TypeFlags.StringOrNumberLiteralOrUnique);
|
||||
stringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) :
|
||||
getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) :
|
||||
getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
|
||||
getLiteralTypeFromProperties(type, TypeFlags.StringOrNumberLiteralOrUnique);
|
||||
}
|
||||
|
||||
function getExtractStringType(type: Type) {
|
||||
@@ -9563,7 +9579,7 @@ namespace ts {
|
||||
// object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates in
|
||||
// an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]'
|
||||
// has always been resolved eagerly using the constraint type of 'this' at the given location.
|
||||
if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) {
|
||||
if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType) && isGenericObjectType(objectType)) {
|
||||
if (objectType.flags & TypeFlags.AnyOrUnknown) {
|
||||
return objectType;
|
||||
}
|
||||
@@ -11013,7 +11029,7 @@ namespace ts {
|
||||
if (!length(node.properties)) return;
|
||||
for (const prop of node.properties) {
|
||||
if (isSpreadAssignment(prop)) continue;
|
||||
const type = getLiteralTypeFromPropertyName(getSymbolOfNode(prop), TypeFlags.StringOrNumberLiteralOrUnique);
|
||||
const type = getLiteralTypeFromProperty(getSymbolOfNode(prop), TypeFlags.StringOrNumberLiteralOrUnique);
|
||||
if (!type || (type.flags & TypeFlags.Never)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts(7,5): error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts(8,5): error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts(6,5): error TS2322: Type '{ [x: string]: string | number; }' is not assignable to type 'I'.
|
||||
Index signatures are incompatible.
|
||||
Type 'string | number' is not assignable to type 'boolean'.
|
||||
Type 'string' is not assignable to type 'boolean'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts (2 errors) ====
|
||||
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts (1 errors) ====
|
||||
interface I {
|
||||
[s: string]: boolean;
|
||||
[s: number]: boolean;
|
||||
}
|
||||
|
||||
var o: I = {
|
||||
~
|
||||
!!! error TS2322: Type '{ [x: string]: string | number; }' is not assignable to type 'I'.
|
||||
!!! error TS2322: Index signatures are incompatible.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'boolean'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
|
||||
[""+"foo"]: "",
|
||||
~~~~~~~~~~
|
||||
!!! error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
|
||||
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts:2:5: The expected type comes from this index signature.
|
||||
[""+"bar"]: 0
|
||||
~~~~~~~~~~
|
||||
!!! error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
|
||||
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES5.ts:2:5: The expected type comes from this index signature.
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts(7,5): error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts(8,5): error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts(6,5): error TS2322: Type '{ [x: string]: string | number; }' is not assignable to type 'I'.
|
||||
Index signatures are incompatible.
|
||||
Type 'string | number' is not assignable to type 'boolean'.
|
||||
Type 'string' is not assignable to type 'boolean'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts (2 errors) ====
|
||||
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts (1 errors) ====
|
||||
interface I {
|
||||
[s: string]: boolean;
|
||||
[s: number]: boolean;
|
||||
}
|
||||
|
||||
var o: I = {
|
||||
~
|
||||
!!! error TS2322: Type '{ [x: string]: string | number; }' is not assignable to type 'I'.
|
||||
!!! error TS2322: Index signatures are incompatible.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'boolean'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
|
||||
[""+"foo"]: "",
|
||||
~~~~~~~~~~
|
||||
!!! error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
|
||||
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts:2:5: The expected type comes from this index signature.
|
||||
[""+"bar"]: 0
|
||||
~~~~~~~~~~
|
||||
!!! error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
|
||||
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType8_ES6.ts:2:5: The expected type comes from this index signature.
|
||||
}
|
||||
@@ -18,20 +18,20 @@ class C<T extends Options> {
|
||||
>method : () => void
|
||||
|
||||
let { a, b } = this.foo;
|
||||
>a : { [P in keyof T]: T[P]; }["a"]
|
||||
>b : { [P in keyof T]: T[P]; }["b"]
|
||||
>a : T["a"]
|
||||
>b : T["b"]
|
||||
>this.foo : { [P in keyof T]: T[P]; }
|
||||
>this : this
|
||||
>foo : { [P in keyof T]: T[P]; }
|
||||
|
||||
!(a && b);
|
||||
>!(a && b) : false
|
||||
>(a && b) : { [P in keyof T]: T[P]; }["b"]
|
||||
>a && b : { [P in keyof T]: T[P]; }["b"]
|
||||
>a : { [P in keyof T]: T[P]; }["a"]
|
||||
>b : { [P in keyof T]: T[P]; }["b"]
|
||||
>(a && b) : T["b"]
|
||||
>a && b : T["b"]
|
||||
>a : T["a"]
|
||||
>b : T["b"]
|
||||
|
||||
a;
|
||||
>a : { [P in keyof T]: T[P]; }["a"]
|
||||
>a : T["a"]
|
||||
}
|
||||
}
|
||||
|
||||
61
tests/baselines/reference/genericObjectRest.js
Normal file
61
tests/baselines/reference/genericObjectRest.js
Normal file
@@ -0,0 +1,61 @@
|
||||
//// [genericObjectRest.ts]
|
||||
const a = 'a';
|
||||
|
||||
function f1<T extends { a: string, b: number }>(obj: T) {
|
||||
let { ...r0 } = obj;
|
||||
let { a: a1, ...r1 } = obj;
|
||||
let { a: a2, b: b2, ...r2 } = obj;
|
||||
let { 'a': a3, ...r3 } = obj;
|
||||
let { ['a']: a4, ...r4 } = obj;
|
||||
let { [a]: a5, ...r5 } = obj;
|
||||
}
|
||||
|
||||
const sa = Symbol();
|
||||
const sb = Symbol();
|
||||
|
||||
function f2<T extends { [sa]: string, [sb]: number }>(obj: T) {
|
||||
let { [sa]: a1, [sb]: b1, ...r1 } = obj;
|
||||
}
|
||||
|
||||
function f3<T, K1 extends keyof T, K2 extends keyof T>(obj: T, k1: K1, k2: K2) {
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
}
|
||||
|
||||
type Item = { a: string, b: number, c: boolean };
|
||||
|
||||
function f4<K1 extends keyof Item, K2 extends keyof Item>(obj: Item, k1: K1, k2: K2) {
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
}
|
||||
|
||||
|
||||
//// [genericObjectRest.js]
|
||||
"use strict";
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
|
||||
t[p[i]] = s[p[i]];
|
||||
return t;
|
||||
};
|
||||
const a = 'a';
|
||||
function f1(obj) {
|
||||
let r0 = __rest(obj, []);
|
||||
let { a: a1 } = obj, r1 = __rest(obj, ["a"]);
|
||||
let { a: a2, b: b2 } = obj, r2 = __rest(obj, ["a", "b"]);
|
||||
let { 'a': a3 } = obj, r3 = __rest(obj, ['a']);
|
||||
let { ['a']: a4 } = obj, r4 = __rest(obj, ['a']);
|
||||
let _a = a, a5 = obj[_a], r5 = __rest(obj, [typeof _a === "symbol" ? _a : _a + ""]);
|
||||
}
|
||||
const sa = Symbol();
|
||||
const sb = Symbol();
|
||||
function f2(obj) {
|
||||
let _a = sa, a1 = obj[_a], _b = sb, b1 = obj[_b], r1 = __rest(obj, [typeof _a === "symbol" ? _a : _a + "", typeof _b === "symbol" ? _b : _b + ""]);
|
||||
}
|
||||
function f3(obj, k1, k2) {
|
||||
let _a = k1, a1 = obj[_a], _b = k2, a2 = obj[_b], r1 = __rest(obj, [typeof _a === "symbol" ? _a : _a + "", typeof _b === "symbol" ? _b : _b + ""]);
|
||||
}
|
||||
function f4(obj, k1, k2) {
|
||||
let _a = k1, a1 = obj[_a], _b = k2, a2 = obj[_b], r1 = __rest(obj, [typeof _a === "symbol" ? _a : _a + "", typeof _b === "symbol" ? _b : _b + ""]);
|
||||
}
|
||||
126
tests/baselines/reference/genericObjectRest.symbols
Normal file
126
tests/baselines/reference/genericObjectRest.symbols
Normal file
@@ -0,0 +1,126 @@
|
||||
=== tests/cases/conformance/types/rest/genericObjectRest.ts ===
|
||||
const a = 'a';
|
||||
>a : Symbol(a, Decl(genericObjectRest.ts, 0, 5))
|
||||
|
||||
function f1<T extends { a: string, b: number }>(obj: T) {
|
||||
>f1 : Symbol(f1, Decl(genericObjectRest.ts, 0, 14))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 2, 12))
|
||||
>a : Symbol(a, Decl(genericObjectRest.ts, 2, 23))
|
||||
>b : Symbol(b, Decl(genericObjectRest.ts, 2, 34))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 2, 12))
|
||||
|
||||
let { ...r0 } = obj;
|
||||
>r0 : Symbol(r0, Decl(genericObjectRest.ts, 3, 9))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
|
||||
let { a: a1, ...r1 } = obj;
|
||||
>a : Symbol(a, Decl(genericObjectRest.ts, 2, 23))
|
||||
>a1 : Symbol(a1, Decl(genericObjectRest.ts, 4, 9))
|
||||
>r1 : Symbol(r1, Decl(genericObjectRest.ts, 4, 16))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
|
||||
let { a: a2, b: b2, ...r2 } = obj;
|
||||
>a : Symbol(a, Decl(genericObjectRest.ts, 2, 23))
|
||||
>a2 : Symbol(a2, Decl(genericObjectRest.ts, 5, 9))
|
||||
>b : Symbol(b, Decl(genericObjectRest.ts, 2, 34))
|
||||
>b2 : Symbol(b2, Decl(genericObjectRest.ts, 5, 16))
|
||||
>r2 : Symbol(r2, Decl(genericObjectRest.ts, 5, 23))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
|
||||
let { 'a': a3, ...r3 } = obj;
|
||||
>a3 : Symbol(a3, Decl(genericObjectRest.ts, 6, 9))
|
||||
>r3 : Symbol(r3, Decl(genericObjectRest.ts, 6, 18))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
|
||||
let { ['a']: a4, ...r4 } = obj;
|
||||
>'a' : Symbol(a4, Decl(genericObjectRest.ts, 7, 9))
|
||||
>a4 : Symbol(a4, Decl(genericObjectRest.ts, 7, 9))
|
||||
>r4 : Symbol(r4, Decl(genericObjectRest.ts, 7, 20))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
|
||||
let { [a]: a5, ...r5 } = obj;
|
||||
>a : Symbol(a, Decl(genericObjectRest.ts, 0, 5))
|
||||
>a5 : Symbol(a5, Decl(genericObjectRest.ts, 8, 9))
|
||||
>r5 : Symbol(r5, Decl(genericObjectRest.ts, 8, 18))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 2, 48))
|
||||
}
|
||||
|
||||
const sa = Symbol();
|
||||
>sa : Symbol(sa, Decl(genericObjectRest.ts, 11, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
|
||||
|
||||
const sb = Symbol();
|
||||
>sb : Symbol(sb, Decl(genericObjectRest.ts, 12, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
|
||||
|
||||
function f2<T extends { [sa]: string, [sb]: number }>(obj: T) {
|
||||
>f2 : Symbol(f2, Decl(genericObjectRest.ts, 12, 20))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 14, 12))
|
||||
>[sa] : Symbol([sa], Decl(genericObjectRest.ts, 14, 23))
|
||||
>sa : Symbol(sa, Decl(genericObjectRest.ts, 11, 5))
|
||||
>[sb] : Symbol([sb], Decl(genericObjectRest.ts, 14, 37))
|
||||
>sb : Symbol(sb, Decl(genericObjectRest.ts, 12, 5))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 14, 54))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 14, 12))
|
||||
|
||||
let { [sa]: a1, [sb]: b1, ...r1 } = obj;
|
||||
>sa : Symbol(sa, Decl(genericObjectRest.ts, 11, 5))
|
||||
>a1 : Symbol(a1, Decl(genericObjectRest.ts, 15, 9))
|
||||
>sb : Symbol(sb, Decl(genericObjectRest.ts, 12, 5))
|
||||
>b1 : Symbol(b1, Decl(genericObjectRest.ts, 15, 19))
|
||||
>r1 : Symbol(r1, Decl(genericObjectRest.ts, 15, 29))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 14, 54))
|
||||
}
|
||||
|
||||
function f3<T, K1 extends keyof T, K2 extends keyof T>(obj: T, k1: K1, k2: K2) {
|
||||
>f3 : Symbol(f3, Decl(genericObjectRest.ts, 16, 1))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 18, 12))
|
||||
>K1 : Symbol(K1, Decl(genericObjectRest.ts, 18, 14))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 18, 12))
|
||||
>K2 : Symbol(K2, Decl(genericObjectRest.ts, 18, 34))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 18, 12))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 18, 55))
|
||||
>T : Symbol(T, Decl(genericObjectRest.ts, 18, 12))
|
||||
>k1 : Symbol(k1, Decl(genericObjectRest.ts, 18, 62))
|
||||
>K1 : Symbol(K1, Decl(genericObjectRest.ts, 18, 14))
|
||||
>k2 : Symbol(k2, Decl(genericObjectRest.ts, 18, 70))
|
||||
>K2 : Symbol(K2, Decl(genericObjectRest.ts, 18, 34))
|
||||
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
>k1 : Symbol(k1, Decl(genericObjectRest.ts, 18, 62))
|
||||
>a1 : Symbol(a1, Decl(genericObjectRest.ts, 19, 9))
|
||||
>k2 : Symbol(k2, Decl(genericObjectRest.ts, 18, 70))
|
||||
>a2 : Symbol(a2, Decl(genericObjectRest.ts, 19, 19))
|
||||
>r1 : Symbol(r1, Decl(genericObjectRest.ts, 19, 29))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 18, 55))
|
||||
}
|
||||
|
||||
type Item = { a: string, b: number, c: boolean };
|
||||
>Item : Symbol(Item, Decl(genericObjectRest.ts, 20, 1))
|
||||
>a : Symbol(a, Decl(genericObjectRest.ts, 22, 13))
|
||||
>b : Symbol(b, Decl(genericObjectRest.ts, 22, 24))
|
||||
>c : Symbol(c, Decl(genericObjectRest.ts, 22, 35))
|
||||
|
||||
function f4<K1 extends keyof Item, K2 extends keyof Item>(obj: Item, k1: K1, k2: K2) {
|
||||
>f4 : Symbol(f4, Decl(genericObjectRest.ts, 22, 49))
|
||||
>K1 : Symbol(K1, Decl(genericObjectRest.ts, 24, 12))
|
||||
>Item : Symbol(Item, Decl(genericObjectRest.ts, 20, 1))
|
||||
>K2 : Symbol(K2, Decl(genericObjectRest.ts, 24, 34))
|
||||
>Item : Symbol(Item, Decl(genericObjectRest.ts, 20, 1))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 24, 58))
|
||||
>Item : Symbol(Item, Decl(genericObjectRest.ts, 20, 1))
|
||||
>k1 : Symbol(k1, Decl(genericObjectRest.ts, 24, 68))
|
||||
>K1 : Symbol(K1, Decl(genericObjectRest.ts, 24, 12))
|
||||
>k2 : Symbol(k2, Decl(genericObjectRest.ts, 24, 76))
|
||||
>K2 : Symbol(K2, Decl(genericObjectRest.ts, 24, 34))
|
||||
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
>k1 : Symbol(k1, Decl(genericObjectRest.ts, 24, 68))
|
||||
>a1 : Symbol(a1, Decl(genericObjectRest.ts, 25, 9))
|
||||
>k2 : Symbol(k2, Decl(genericObjectRest.ts, 24, 76))
|
||||
>a2 : Symbol(a2, Decl(genericObjectRest.ts, 25, 19))
|
||||
>r1 : Symbol(r1, Decl(genericObjectRest.ts, 25, 29))
|
||||
>obj : Symbol(obj, Decl(genericObjectRest.ts, 24, 58))
|
||||
}
|
||||
|
||||
110
tests/baselines/reference/genericObjectRest.types
Normal file
110
tests/baselines/reference/genericObjectRest.types
Normal file
@@ -0,0 +1,110 @@
|
||||
=== tests/cases/conformance/types/rest/genericObjectRest.ts ===
|
||||
const a = 'a';
|
||||
>a : "a"
|
||||
>'a' : "a"
|
||||
|
||||
function f1<T extends { a: string, b: number }>(obj: T) {
|
||||
>f1 : <T extends { a: string; b: number; }>(obj: T) => void
|
||||
>a : string
|
||||
>b : number
|
||||
>obj : T
|
||||
|
||||
let { ...r0 } = obj;
|
||||
>r0 : T
|
||||
>obj : T
|
||||
|
||||
let { a: a1, ...r1 } = obj;
|
||||
>a : any
|
||||
>a1 : string
|
||||
>r1 : Pick<T, Exclude<keyof T, "a">>
|
||||
>obj : T
|
||||
|
||||
let { a: a2, b: b2, ...r2 } = obj;
|
||||
>a : any
|
||||
>a2 : string
|
||||
>b : any
|
||||
>b2 : number
|
||||
>r2 : Pick<T, Exclude<keyof T, "a" | "b">>
|
||||
>obj : T
|
||||
|
||||
let { 'a': a3, ...r3 } = obj;
|
||||
>a3 : string
|
||||
>r3 : Pick<T, Exclude<keyof T, "a">>
|
||||
>obj : T
|
||||
|
||||
let { ['a']: a4, ...r4 } = obj;
|
||||
>'a' : "a"
|
||||
>a4 : string
|
||||
>r4 : Pick<T, Exclude<keyof T, "a">>
|
||||
>obj : T
|
||||
|
||||
let { [a]: a5, ...r5 } = obj;
|
||||
>a : "a"
|
||||
>a5 : string
|
||||
>r5 : Pick<T, Exclude<keyof T, "a">>
|
||||
>obj : T
|
||||
}
|
||||
|
||||
const sa = Symbol();
|
||||
>sa : unique symbol
|
||||
>Symbol() : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
|
||||
const sb = Symbol();
|
||||
>sb : unique symbol
|
||||
>Symbol() : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
|
||||
function f2<T extends { [sa]: string, [sb]: number }>(obj: T) {
|
||||
>f2 : <T extends { [sa]: string; [sb]: number; }>(obj: T) => void
|
||||
>[sa] : string
|
||||
>sa : unique symbol
|
||||
>[sb] : number
|
||||
>sb : unique symbol
|
||||
>obj : T
|
||||
|
||||
let { [sa]: a1, [sb]: b1, ...r1 } = obj;
|
||||
>sa : unique symbol
|
||||
>a1 : string
|
||||
>sb : unique symbol
|
||||
>b1 : number
|
||||
>r1 : Pick<T, Exclude<keyof T, unique symbol | unique symbol>>
|
||||
>obj : T
|
||||
}
|
||||
|
||||
function f3<T, K1 extends keyof T, K2 extends keyof T>(obj: T, k1: K1, k2: K2) {
|
||||
>f3 : <T, K1 extends keyof T, K2 extends keyof T>(obj: T, k1: K1, k2: K2) => void
|
||||
>obj : T
|
||||
>k1 : K1
|
||||
>k2 : K2
|
||||
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
>k1 : K1
|
||||
>a1 : T[K1]
|
||||
>k2 : K2
|
||||
>a2 : T[K2]
|
||||
>r1 : Pick<T, Exclude<keyof T, K1 | K2>>
|
||||
>obj : T
|
||||
}
|
||||
|
||||
type Item = { a: string, b: number, c: boolean };
|
||||
>Item : Item
|
||||
>a : string
|
||||
>b : number
|
||||
>c : boolean
|
||||
|
||||
function f4<K1 extends keyof Item, K2 extends keyof Item>(obj: Item, k1: K1, k2: K2) {
|
||||
>f4 : <K1 extends "a" | "b" | "c", K2 extends "a" | "b" | "c">(obj: Item, k1: K1, k2: K2) => void
|
||||
>obj : Item
|
||||
>k1 : K1
|
||||
>k2 : K2
|
||||
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
>k1 : K1
|
||||
>a1 : Item[K1]
|
||||
>k2 : K2
|
||||
>a2 : Item[K2]
|
||||
>r1 : Pick<Item, Exclude<"a", K1 | K2> | Exclude<"b", K1 | K2> | Exclude<"c", K1 | K2>>
|
||||
>obj : Item
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ tests/cases/conformance/types/rest/objectRest.ts(7,12): error TS2339: Property '
|
||||
tests/cases/conformance/types/rest/objectRest.ts(7,20): error TS2339: Property '1' does not exist on type 'String'.
|
||||
tests/cases/conformance/types/rest/objectRest.ts(43,8): error TS2537: Type '{ a: number; b: string; }' has no matching index signature for type 'string'.
|
||||
tests/cases/conformance/types/rest/objectRest.ts(43,35): error TS2537: Type '{ a: number; b: string; }' has no matching index signature for type 'string'.
|
||||
tests/cases/conformance/types/rest/objectRest.ts(43,57): error TS2403: Subsequent variable declarations must have the same type. Variable 'o' must be of type '{ a: number; b: string; }', but here has type '{}'.
|
||||
tests/cases/conformance/types/rest/objectRest.ts(44,53): error TS2322: Type '{}' is not assignable to type '{ a: number; b: string; }'.
|
||||
Property 'a' is missing in type '{}'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/rest/objectRest.ts (4 errors) ====
|
||||
==== tests/cases/conformance/types/rest/objectRest.ts (6 errors) ====
|
||||
var o = { a: 1, b: 'no' }
|
||||
var { ...clone } = o;
|
||||
var { a, ...justB } = o;
|
||||
@@ -56,7 +59,12 @@ tests/cases/conformance/types/rest/objectRest.ts(43,35): error TS2537: Type '{ a
|
||||
!!! error TS2537: Type '{ a: number; b: string; }' has no matching index signature for type 'string'.
|
||||
~~~~~~~~~
|
||||
!!! error TS2537: Type '{ a: number; b: string; }' has no matching index signature for type 'string'.
|
||||
~
|
||||
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o' must be of type '{ a: number; b: string; }', but here has type '{}'.
|
||||
({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o);
|
||||
~
|
||||
!!! error TS2322: Type '{}' is not assignable to type '{ a: number; b: string; }'.
|
||||
!!! error TS2322: Property 'a' is missing in type '{}'.
|
||||
|
||||
var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
|
||||
|
||||
@@ -5,11 +5,10 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(6,10): error TS2322: Ty
|
||||
tests/cases/conformance/types/rest/objectRestNegative.ts(9,31): error TS2462: A rest element must be last in a destructuring pattern.
|
||||
tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: Member 'x' implicitly has an 'any' type.
|
||||
tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type.
|
||||
tests/cases/conformance/types/rest/objectRestNegative.ts(12,17): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/rest/objectRestNegative.ts (7 errors) ====
|
||||
==== tests/cases/conformance/types/rest/objectRestNegative.ts (6 errors) ====
|
||||
let o = { a: 1, b: 'no' };
|
||||
var { ...mustBeLast, a } = o;
|
||||
~~~~~~~~~~
|
||||
@@ -34,8 +33,6 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th
|
||||
~
|
||||
!!! error TS7008: Member 'y' implicitly has an 'any' type.
|
||||
let { x, ...rest } = t;
|
||||
~~~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
return rest;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,18 +36,18 @@ function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
|
||||
>b : string
|
||||
}
|
||||
function generic<T extends { x, y }>(t: T) {
|
||||
>generic : <T extends { x: any; y: any; }>(t: T) => any
|
||||
>generic : <T extends { x: any; y: any; }>(t: T) => Pick<T, Exclude<keyof T, "x">>
|
||||
>x : any
|
||||
>y : any
|
||||
>t : T
|
||||
|
||||
let { x, ...rest } = t;
|
||||
>x : any
|
||||
>rest : any
|
||||
>rest : Pick<T, Exclude<keyof T, "x">>
|
||||
>t : T
|
||||
|
||||
return rest;
|
||||
>rest : any
|
||||
>rest : Pick<T, Exclude<keyof T, "x">>
|
||||
}
|
||||
|
||||
let rest: { b: string }
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(27,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(29,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(30,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(31,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(33,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(36,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(37,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(39,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(40,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(42,13): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(43,13): error TS2700: Rest types may only be created from object types.
|
||||
@@ -16,7 +10,7 @@ tests/cases/compiler/restInvalidArgumentType.ts(51,13): error TS2700: Rest types
|
||||
tests/cases/compiler/restInvalidArgumentType.ts(53,13): error TS2700: Rest types may only be created from object types.
|
||||
|
||||
|
||||
==== tests/cases/compiler/restInvalidArgumentType.ts (16 errors) ====
|
||||
==== tests/cases/compiler/restInvalidArgumentType.ts (10 errors) ====
|
||||
enum E { v1, v2 };
|
||||
|
||||
function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
@@ -44,34 +38,22 @@ tests/cases/compiler/restInvalidArgumentType.ts(53,13): error TS2700: Rest types
|
||||
var a: any;
|
||||
|
||||
var {...r1} = p1; // Error, generic type paramterre
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
var {...r2} = p2; // OK
|
||||
var {...r3} = t; // Error, generic type paramter
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
var {...r4} = i; // Error, index access
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
var {...r5} = k; // Error, index
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
|
||||
var {...r6} = mapped_generic; // Error, generic mapped object type
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
var {...r7} = mapped; // OK, non-generic mapped type
|
||||
|
||||
var {...r8} = union_generic; // Error, union with generic type parameter
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
var {...r9} = union_primitive; // Error, union with generic type parameter
|
||||
~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
|
||||
var {...r10} = intersection_generic; // Error, intersection with generic type parameter
|
||||
~~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
var {...r11} = intersection_primitive; // Error, intersection with generic type parameter
|
||||
~~~
|
||||
!!! error TS2700: Rest types may only be created from object types.
|
||||
|
||||
@@ -67,7 +67,7 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
>a : any
|
||||
|
||||
var {...r1} = p1; // Error, generic type paramterre
|
||||
>r1 : any
|
||||
>r1 : T
|
||||
>p1 : T
|
||||
|
||||
var {...r2} = p2; // OK
|
||||
@@ -75,11 +75,11 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
>p2 : T[]
|
||||
|
||||
var {...r3} = t; // Error, generic type paramter
|
||||
>r3 : any
|
||||
>r3 : T
|
||||
>t : T
|
||||
|
||||
var {...r4} = i; // Error, index access
|
||||
>r4 : any
|
||||
>r4 : T["b"]
|
||||
>i : T["b"]
|
||||
|
||||
var {...r5} = k; // Error, index
|
||||
@@ -87,7 +87,7 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
>k : keyof T
|
||||
|
||||
var {...r6} = mapped_generic; // Error, generic mapped object type
|
||||
>r6 : any
|
||||
>r6 : { [P in keyof T]: T[P]; }
|
||||
>mapped_generic : { [P in keyof T]: T[P]; }
|
||||
|
||||
var {...r7} = mapped; // OK, non-generic mapped type
|
||||
@@ -95,7 +95,7 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
>mapped : { b: T["b"]; }
|
||||
|
||||
var {...r8} = union_generic; // Error, union with generic type parameter
|
||||
>r8 : any
|
||||
>r8 : T | { a: number; }
|
||||
>union_generic : T | { a: number; }
|
||||
|
||||
var {...r9} = union_primitive; // Error, union with generic type parameter
|
||||
@@ -103,7 +103,7 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
>union_primitive : number | { a: number; }
|
||||
|
||||
var {...r10} = intersection_generic; // Error, intersection with generic type parameter
|
||||
>r10 : any
|
||||
>r10 : T & { a: number; }
|
||||
>intersection_generic : T & { a: number; }
|
||||
|
||||
var {...r11} = intersection_primitive; // Error, intersection with generic type parameter
|
||||
|
||||
30
tests/cases/conformance/types/rest/genericObjectRest.ts
Normal file
30
tests/cases/conformance/types/rest/genericObjectRest.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// @strict: true
|
||||
// @target: es2015
|
||||
|
||||
const a = 'a';
|
||||
|
||||
function f1<T extends { a: string, b: number }>(obj: T) {
|
||||
let { ...r0 } = obj;
|
||||
let { a: a1, ...r1 } = obj;
|
||||
let { a: a2, b: b2, ...r2 } = obj;
|
||||
let { 'a': a3, ...r3 } = obj;
|
||||
let { ['a']: a4, ...r4 } = obj;
|
||||
let { [a]: a5, ...r5 } = obj;
|
||||
}
|
||||
|
||||
const sa = Symbol();
|
||||
const sb = Symbol();
|
||||
|
||||
function f2<T extends { [sa]: string, [sb]: number }>(obj: T) {
|
||||
let { [sa]: a1, [sb]: b1, ...r1 } = obj;
|
||||
}
|
||||
|
||||
function f3<T, K1 extends keyof T, K2 extends keyof T>(obj: T, k1: K1, k2: K2) {
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
}
|
||||
|
||||
type Item = { a: string, b: number, c: boolean };
|
||||
|
||||
function f4<K1 extends keyof Item, K2 extends keyof Item>(obj: Item, k1: K1, k2: K2) {
|
||||
let { [k1]: a1, [k2]: a2, ...r1 } = obj;
|
||||
}
|
||||
Reference in New Issue
Block a user