When using a default export, if the expression consists only of a variable identifier, the type inferencer defaults to the declaration of the variable instead of the actual type of the expression. Is this behavior intentional or is it a bug?
// b.ts
const v: string | number = 0;
export default v;
// working alternatives:
// export default (v);
// export default v as typeof v;
// a.ts
import v from './b';
v.toFixed(2); // error
To force the inference of the expression's type, you can use various methods like demonstrated above.
While the information provided should be clear on its own, here is additional context to prevent any misconceptions. I came across this issue while attempting to merge a symbol with a function:
// b.ts
const sy = Symbol();
const merge: <F extends (...args: any) => any>(f: F) => asserts f is F & { [sy]: string }
= f => (f as any)[sy] = 'something';
const f = () => {};
merge(f);
export default f; // retains original type
A potential solution would be
export default Object.assign(f, { [sy]: 'something' });
, but it's ideal to have an inlined assignment as seen in JavaScript equivalents. Please note that the code above may face another issue when re-exporting the import, which I have discussed in another question. It might feel like a bug, but further clarification is needed.