-
Notifications
You must be signed in to change notification settings - Fork 13k
Description
Bug Report
π Search Terms
modifiers declaration dts emit mapped type omit pick
π Version & Regression Information
- This is the behavior in every version I tried (at least since 4.7)
β― Playground Link
The repro case involves multiple files, 2 packages and declaration emit so I had to prepare a repository with it:
https://github.com/Andarist/mapped-type-emit-loses-modifiers-bug
π» Code
// packages/pkg-a/src/other.ts
// how Omit from lib is defined
type OmitReal<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
// what we see when we hover it
type OmitUnveiled<T, K extends string | number | symbol> = {
[P in Exclude<keyof T, K>]: T[P];
};
export function test1<T, K extends string>(obj: T, k: K): OmitReal<T, K> {
return {} as any;
}
export function test2<T, K extends string>(obj: T, k: K): OmitUnveiled<T, K> {
return {} as any;
}
// packages/pkg-a/src/index.ts
import { test1, test2 } from "./other";
export function wrappedTest1<T, K extends string>(obj: T, k: K) {
return test1(obj, k);
}
export function wrappedTest2<T, K extends string>(obj: T, k: K) {
return test2(obj, k);
}
export type Obj = {
a: number;
readonly foo: string;
};
export const processedInternally1 = wrappedTest1({} as Obj, "a");
export const processedInternally2 = wrappedTest2({} as Obj, "a");
// packages/pkg-b/src/index.ts
import { wrappedTest1, wrappedTest2, Obj } from "pkg-a";
export const processedExternally1 = wrappedTest1({} as Obj, "a");
export const processedExternally2 = wrappedTest2({} as Obj, "a");
π Actual behavior
The mapped type starts to lose modifiers when it's emitted even though modifiers are retained when the same thing is used within the package.
This can be seen in the emitted .d.ts
for each of those packages. Both are using the same function and the same arguments but yet the type emitted in both places is different:
In pkg-a
we can see this:
export declare const processedInternally1: {
readonly foo: string;
};
export declare const processedInternally2: {
foo: string;
};
In pkb-b
we can see this:
export declare const processedExternally1: {
foo: string;
};
export declare const processedExternally2: {
foo: string;
};
It all starts with the fact that OmitReal
and OmitUnveiled
are not exported from packages/pkg-a/src/other.ts
so packages/pkg-a/types/index.d.ts
has to inline them in its declarations and both end up being emitted the same (here):
export declare function wrappedTest1<T, K extends string>(obj: T, k: K): { [P in Exclude<keyof T, K>]: T[P]; };
export declare function wrappedTest2<T, K extends string>(obj: T, k: K): { [P in Exclude<keyof T, K>]: T[P]; };
Their original declarations have different traits when it comes to preserving property modifiers though and thus this is a bug.
π Expected behavior
I would expect the emitted declaration to behave in the same way as the original one.