Repository: TypeScript
Issue: Homomorphic mapped type with type substitution produces declaration file with error
Labels: Needs Investigation

# Bug Report

### 🔎 Search Terms

- mapped types
- homomorphic
- declaration file error

### 🕗 Version & Regression Information

- This is the behavior in every version I tried, and I reviewed the FAQ for entries about homomorphic mapped types

### ⏯ Playground Link

[Source code](https://www.typescriptlang.org/play?#code/PTAEBUAsEsGdQMYEMB2oBGBTUTQBcBPAB2z0iT1GhQQBsBXAE03gAN6VmAzazR10I3qkA9qEgiAtlJEAnIjAShJSIiUb5iLAHQAoTAA8icyoRKgAciJQAxDgjzRrAaUwFYAHnAA+UAF5QAG9dUFAAbWcqNABrNxEuCABdAC4ICMTQQzxMTng7GkdrUAB+UBRMADdMWVBU5wBuXQBfMNiCeKTGkFAAeUloPA9fRhEWMpFKJFpaEQB3UHZOTB5y-iiqPHhYTARrDQBzHOroBAAaDHpKAap4Y1hYaHRabC45fHJTMXI1HMFhfDEZGwEmk0lkkCIJ2UqnUmhI8Cw5AqThqXFkUhw6BEVT0hmMslMWl6VVks1kA0wXnOPV8AT6Ayplms+QcThQrncHhpvgAZL1GvojCY4dgAAroojwOkkskUjwhIL4Fh4YqpLEiZ6oUBNU4K4KhULZWAq1IoeiSLCyRoGpXGgBMqtAAAoAJT+XwVETQRjW7W6bwCrj2QpoBCyTAUTAskNebyu1JOvCpcCgPmBUCwKSYMjUfZqkQaiNoJpuvwer0afXhvD0WRoV3uoJNRpNXSC-GUXYoY2IcORxjRtn+XsR7KD6wecUiSVxl2NIA)
[Emitted declaration file](https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBAE2AYwDYEMrDjAnmbAOQgDsAxAVxORgEtSBpYXAZwB4AVAPjgF44A3gCg4ouAG0GcWiTgBrZhABmcDgF0AXKslq4oGMBIIWcStTqk4AfjglgAN2BQ4WhgG4hAX3ELcy1WoeoJCwiCgYWDj42ADyjlAA7lC0BpwANHAxPPwxALYp6XDE5FQ09CRMrGxZPABkmUHg0PBIaJjYeARwAApQEGAmOfFJKcBswmI4wCwwVloARhAQqMDoJB6eGRNiBjNzthS5804ek7swAEz7ABQAlHw89hC0CBtcjSEt4e1wyKQzvyw6AMCDMZVIWmuMC0eQK21E532i2Wq1kAB84FQkEoZMBXkIAPQE1QAC1oJjAfQQFGQ0zgaz0UD6zmOyHQFBY2BScCBqFoAC86TAScC4AADYpgiwVZgsMVwBK0VCoOCUiDU2nirHAHF2BDymQ4MkmNmchVk5Ak6QmEgQeDoZUQBJ4+kmYXYTl-IxwADmhictGQOAg4thMDFADovBlJaVpZV2PCpnstCRDsdnBjtbq8acdtNLjc7g84E8Xvcs0Ydbj8Z4uHVBCJ8ymDkcnHBK9ia3mEQWrpDi7xHs8EBXMVWc7W4PUkywILlgMKZD6FksVmsNvch6WR24gA)

### 💻 Code

Source code which type-checks without error:

```ts
// This can be a type that includes `undefined` due to homomorphic mapped types.
export type NonFunctionKeys<T> = {
  [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
// Omit<> does not allow `undefined` in its second generic, but it is possible for that to happen due to the homomorhpic mapped types behavior from above.
export type Overwrite<T, O> = Omit<T, NonFunctionKeys<O>> & O;

export type Props = Overwrite<
  { test?: boolean },
  {
    test?: number;
    test2?: () => void;
  }
>;

function createFunction<T>(): (t: T & { something: boolean }) => void {
 return () => {};
}

export const createdFunction = createFunction<Props>();
```

The above source code emits this declaration file which produces an error when type-checked:

```ts
export declare type NonFunctionKeys<T> = {
    [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
export declare type Overwrite<T, O> = Omit<T, NonFunctionKeys<O>> & O;
export declare type Props = Overwrite<{
    test?: boolean;
}, {
    test?: number;
    test2?: () => void;
}>;
export declare const createdFunction: (t: Omit<{
    test?: boolean | undefined;
// This produces an error because it realizes that `NonFunctionKeys` will produce `undefined` in this case which is not allowed as the second generic to `Omit`.
}, NonFunctionKeys<{
    test?: number | undefined;
    test2?: (() => void) | undefined;
}>> & {
    test?: number | undefined;
    test2?: (() => void) | undefined;
} & {
    something: boolean;
}) => void;
```

### 🙁 Actual behavior

There is no error for the source code and it successfully emits a declaration file. The emitted declaration file has an error in it.

### 🙂 Expected behavior

Either the source code should not successfully type-check or it should produce a declaration file that does successfully type-check.

This intended behavior of homomorphic mapped types in regards to this scenario are documented in https://github.com/microsoft/TypeScript/issues/34992 and https://github.com/microsoft/TypeScript/issues/40190. The workaround presented in those issues would successfully fix the declaration file in this case. However it was not brought up in those issues that the underlying behavior could produce a declaration file that has an error. From what I understand, it is desirable that if the source-code type-checks successfully that the emitted declaration file should also type-check successfully. This seems especially important due to the prolific and encouraged use of `skipLibCheck` which seems to be defended with the reasoning that all emitted declaration files will type-check successfully.