21

I have one interface with many fields and other interface with almost all fields (just one less).

How in TypeScript without untyped unsafe crutches (<>, as, any, unknown and similar) can one exclude fields in object spread (so without enumerating every field I want to copy)?

interface A {
    fieldA: number;
    fieldB: string;
    fieldC: number;
    fieldD: string;
    fieldE: number;
    fieldF: string;
}

interface B {
    fieldA: number;
    fieldB: string;
    fieldC: number;
    fieldD: string;
    fieldE: number;
    // no fieldF here
}

const a: A = {
    fieldA: 1,
    fieldB: 'b',
    fieldC: 3,
    fieldD: 'd',
    fieldE: 5,
    fieldF: 'f'
}

const b: B = {
    ...a,
    fieldF: undefined
};

This doesn't compile, because fieldF is still present, only have a value of undefined.

2 Answers 2

52

If you don't mind an intermediate step, you can do something like this:

const { fieldF, ...everythingExceptF } = a;
const b: B = everythingExceptF;

This combines the spread and rest operators. The compiler seemed happy with this on my machine, and it gives me the result you'd expect.

Note: this will also create the constant fieldF, which you may or may not want. If you already need that name for some other reason in the same scope, you can reassign it like this:

const { fieldF: someOtherName, ...everythingExceptF } = a;
2
  • This is a nice way to do it, but unfortunately it will throw an error if linting no-unused-vars
    – Dylan w
    Commented Sep 15, 2022 at 3:21
  • 5
    That's true - depending on the linter and your configuration you'll either need to prefix the variable with "_" to flag it as intentionally unused or just annotate that error away. Commented Sep 15, 2022 at 13:09
1

If you wan to remove the field you can:

const copy: A = {
    ...a
};

delete copy.fieldF;

const b: B = copy;

But you don't have to:

const b: B = {
    ...a
};

Compiler is ok with it.

Not the answer you're looking for? Browse other questions tagged or ask your own question.