I have a type for which I want to be able to have exactly one property undefined.
For example, if I had
type MyType = {
  a: number;
  b: number;
  c: number;
};
I would expect OneUndefined<MyType>
to be
  | {
      a?: undefined;
      b: number;
      c: number;
    }
  | {
      a: number;
      b?: undefined;
      c: number;
    }
  | {
      a: number;
      b: number;
      c?: undefined;
    };
Would also be interested in the inverse, OneDefined<T>, or NDefined<T, n>, where exactly n properties are defined.
I have tried forming a type based on similar questions regarding a certain number of properties:
https://stackoverflow.com/a/49725198
https://stackoverflow.com/a/62163715/10252820
However have been unable to make these fit the question being asked here.
Ok I managed to come to an answer for the case of OneUndefined<T>:
type OneUndefined<T> = {
  [K in keyof T]: {
    [P in K]?: undefined;
  } & Omit<T, K>;
}[keyof T];
type MyType = {
  a: number;
  b: number;
  c: number;
};
// valid
const valid1: OneUndefined<MyType> = {
  a: 1,
  b: undefined,
  c: 3,
};
// valid
const valid2: OneUndefined<MyType> = {
  a: 1,
  b: 2,
};
// rejected
const invalid1: OneUndefined<MyType> = {
  a: 1,
  b: 2,
  c: 3,
};
// rejected
const invalid2: OneUndefined<MyType> = {
  a: 1,
  b: undefined,
  c: undefined,
};
For MyType
This section:
  [K in keyof T]: {
    [P in K]?: undefined;
  } & Omit<T, K>;
Generates this:
{
  a: {
    a?: undefined;
    b: number;
    c: number;
  };
  b: {
    a: number;
    b?: undefined;
    c: number;
  };
  c: {
    a: number;
    b: number;
    c?: undefined;
  };
};
Then this }[keyof T]; picks one of the props from the type we just generated.
Edit:
OneDefined<T> is similar:
type OneDefined<T> = {
  [K in keyof T]: {
    [P in K]: T[P];
  } & { [P in keyof Omit<T, K>]?: undefined };
}[keyof T];
                        I managed to come up with an NDefined<T, N> approach using recursive generic types.
type MyType = {
  a: number;
  b: number;
  c: number;
};
type NDefined<
  T extends Record<PropertyKey, unknown>,
  N extends number,
  R extends (keyof T)[] = [],
> = N extends R["length"]
  ? HasDuplicates<R> extends true
    ? never
    : Partial<T> & Required<Pick<T, R[number]>>
  : {
      [K in keyof T]: NDefined<T, N, [...R, K]>;
    }[keyof T];
type HasDuplicates<T extends unknown[]> = T extends [infer L, ...infer R]
  ? L extends R[number]
    ? true
    : HasDuplicates<R>
  : false;
type Result = NDefined<MyType, 2>;
//   ^? type Result = (Partial<MyType> & Required<Pick<MyType, "a" | "b">>)
//                  | (Partial<MyType> & Required<Pick<MyType, "a" | "c">>)
//                  | (Partial<MyType> & Required<Pick<MyType, "b" | "c">>)
TypeScript Playground
First, compute all possible permutations of keyof T as tuples with length N. E. g. with NDefined<{a: any, b: any, c: any}, 2> we get  ["a", "a"] | ["a", "b"] | ["a", "c"] | ["b", "a"] | ["b", "b"] | ["b", "c"] | ["c", "a"] | ["c", "b"] | ["c", "c"]. These tuples mark all the required keys. Tuples that contain duplicates such as ["a", "a"] can be detected with the following helper type (inspired by this answer).
type HasDuplicates<T extends unknown[]> = T extends [infer L, ...infer R]
  ? L extends R[number]
    ? true
    : HasDuplicates<R>
  : false;
It's a bit unelegant to use an extra type for this yet I couldn't find a way to prevent such duplicates directly in the recursive call without getting circular reference errors.
Finally, we can compute the valid object (Record) type permutations with Partial<T> & Required<Pick<T, R[number]>>. This intersection type essentially marks all keys as optional (Partial) except for the tuple keys subsets that we transform into a union using indexed access types and then mark as Required. This works due to distributive conditional types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With