Make a single property optional in TypeScript

In TypeScript, 2.2...

Let's say I have a Person type:

interface Person {
  name: string;
  hometown: string;
  nickname: string;
}

And I'd like to create a function that returns a Person, but doesn't require a nickname:

function makePerson(input: ???): Person {
  return {...input, nickname: input.nickname || input.name};
}

What should be the type of input? I'm looking for a dynamic way to specify a type that is identical to Person except that nickname is optional (nickname?: string | undefined). The closest thing I've figured out so far is this:

type MakePersonInput = Partial<Person> & {
  name: string;
  hometown: string;
}

but that's not quite what I'm looking for, since I have to specify all the types that are required instead of the ones that are optional.


You can also do something like this, partial only some of the keys.

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

interface Person {
  name: string;
  hometown: string;
  nickname: string;
}

type MakePersonInput = PartialBy<Person, 'nickname'>

Here is my Typescript 3.5+ Optional utility type

type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

// and your use case
type MakePersonInput = Optional<Person, 'nickname'>

// and if you wanted to make the hometown optional as well
type MakePersonInput = Optional<Person, 'hometown' | 'nickname'>

For a plug and play solution, consider using the brilliant utility-types package:

npm i utility-types --save

Then simply make use of Optional<T, K>:

import { Optional } from 'utility-types';

type Person = {
  name: string;
  hometown: string;
  nickname: string;
}

type PersonWithOptionalNickname = Optional<Person, 'nickname'>;

// Expect:
//
// type PersonWithOptionalNickname {
//   name: string;
//   hometown: string;
//   nickname?: string;
// }

Update:

As of TypeScript 2.8, this is supported much more concisely by Conditional Types! So far, this also seems to be more reliable than previous implementations.

type Overwrite<T1, T2> = {
    [P in Exclude<keyof T1, keyof T2>]: T1[P]
} & T2;

interface Person {
  name: string;
  hometown: string;
  nickname: string;
}

type MakePersonInput = Overwrite<Person, {
  nickname?: string;
}>

function makePerson(input: MakePersonInput): Person {
  return {...input, nickname: input.nickname || input.name};
}

As before, MakePersonInput is equivalent to:

type MakePersonInput = {
    name: string;
    hometown: string;
} & {
    nickname?: string;
}

Outdated:

As of TypeScript 2.4.1, it looks like there's another option available, as proposed by GitHub user ahejlsberg in a thread on type subtraction: https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-307871458

type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
type Overwrite<T, U> = { [P in Diff<keyof T, keyof U>]: T[P] } & U;

interface Person {
  name: string;
  hometown: string;
  nickname: string;
}
type MakePersonInput = Overwrite<Person, {
  nickname?: string
}>
function makePerson(input: MakePersonInput): Person {
  return {...input, nickname: input.nickname || input.name};
}

According to Intellisense, MakePersonInput is equivalent to:

type MakePersonInput = {
    name: string;
    hometown: string;
} & {
    nickname?: string;
}

which looks a little funny but absolutely gets the job done.

On the downside, I'm gonna need to stare at that Diff type for a while before I start to understand how it works.