Skip to content

Instantly share code, notes, and snippets.

@alloy
Last active March 27, 2024 08:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alloy/cd945f6bdce9abb5c0e0ca57e1873137 to your computer and use it in GitHub Desktop.
Save alloy/cd945f6bdce9abb5c0e0ca57e1873137 to your computer and use it in GitHub Desktop.
Why does TypeScript inline the typeof type?
const x = {
foo: "bar",
answer: 42
}
type X = typeof x
export default {
get X(): X {
return x
}
}
declare const x: {
foo: string;
answer: number;
};
declare type X = typeof x;
declare const _default: {
// Why inline the type here?
readonly X: {
foo: string;
answer: number;
};
};
export default _default;
declare const x: {
foo: string;
answer: number;
};
declare type X = typeof x;
declare const _default: {
// Just use the named type reference
readonly X: X;
};
export default _default;
@alloy
Copy link
Author

alloy commented Feb 16, 2020

I thought I had a solution by capturing the type as an interface:

export const x = {
    foo: "bar",
    answer: 42
}

// Capturing the type as an interface will stop tsc from inlining the type.
type _X = typeof x
interface X extends _X {}

export default {
    get X(): X {
        return x
    }
}

However, that unfortunately doesn’t work with unions:

An interface can only extend an object type or intersection of object types with statically known members. ts(2312)

@alloy
Copy link
Author

alloy commented Feb 17, 2020

Ok, the solution looks to be to “brand” the type, making it a nominal type:

type UniqueBranding = { " Thou shalt ignore this here prop or risketh a runtime mad as a bag of ferrets."?: never };
type X = typeof x & UniqueBranding

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment