I've successfully used typescript "module augmentation" in the past as a temporary workaround when the type declarations from DefinitelyTyped lagged behind the underlying javascript library. The type definitions were always contained in a single file, however, and a new version of a particular public library I'm using has broken the definitions into multiple modules with re-exporting, etc.
In the past this would have worked, but now it doesn't:
import * as Sequelize from 'sequelize';
declare module 'sequelize' {
interface HasManyOptions {
sourceKey?: string;
}
So how can I add add sourceKey to the HasManyOptions interface with the file structure below? I've tried messing with the name of the imported module and nesting module declarations, but no love. I'm stumped.
index.d.ts
export * from './lib/sequelize'
./lib/sequelize.d.ts
export * from './associations/index'
./lib/associations/index.d.ts
export * from './has-many'
./lib/associations/has-many.d.ts
export interface HasManyOptions extends ManyToManyOptions {
keyType?: DataType
...
}
Thanks for the repro case @BillyB. You want this:
import { ManyToManyOptions, DataType } from 'sequelize'
declare module 'sequelize' {
interface HasManyOptions extends ManyToManyOptions {
/**
* A string or a data type to represent the identifier in the table
*/
keyType?: DataType
sourceKey?: string
}
}
Module augmentations aren't super well documented. Here's how this works:
declare module 'sequelize'
, telling TS that you're declaring the sequelize
module. The way name merging works in TS, TS will merge all modules with the exact path 'sequelize'
into one module.extends
clauses and type parameters). So we have to copy keyType
over from the source declaration, which is a little gross.I would file a bug in TypeScript's issue tracker for this. It's surprising that TSC didn't error when you tried to declare an interface with the same exact name as an existing name as an augmentation (shadowing the original name). TSC should either throw an exception that your module exports two unrelated interfaces with the same name, or TS should not take extends
clauses into account when performing interface merging (at least in the specific case of module augmentations).
This is working on my machine:
sequelize.d.ts
import 'sequelize';
declare module 'sequelize' {
interface ManyToManyOptions {
sourceKey?: string;
}
}
index.ts
import { ManyToManyOptions, AssociationOptions } from 'sequelize';
const options: AssociationOptions = {};
const optionsToo: ManyToManyOptions = {
sourceKey: 'foo',
};
https://github.com/shaunluttin/typescript-module-augmentation-sequelize
Edit: This is the fix that worked for BillyB.
To recap for future readers, a 2 part solution to my problem: In these multi-file situations with re-exported declarations the module augmention needed to be in a separate file for some reason; this was not the case in a single typings file. Second, if you are augmenting interfaces that extend other interfaces, you must repeat the extends portion of the declaration; again this was not necessary with a single typing file.
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