2

I am building a software that uses WebSocket with the package NodeJS ws. I organised my networking around a module that is charged of receiving and sending the messages. Because i am using TypeScript, I want to use the type checking which can be pretty handy sometimes. So I constructed two types:

// networking.ts
export class Message {
    constructor(
        public request: string,
        public params: Params) {}
}

export interface Params {
    messageId?: number;
}

This works fine as long as I am only required to use messageId as a parameter. But what if I need to also send a nickname as a parameter ? I could add it to the Params definition but I don't want the networking engine to bother to know all the different parameters that can be sent (you can imagine that I have actually more than one parameter to send)...

Is there a way to do something like:

// profile-params.ts
export interface Params {
    nickname:string;
}

// admin-params.ts
export interface Params {
    authorizations: string[];
}

Such that in the end, the declaration of Params can be merged ? I looked at the official documentation but it can't make it work on different files.

Thanks

3 Answers 3

2

@Daniel W Strimpel is ok, if your interface does not come from a module and you are ok with putting it in the global scope.

If you want the interface to be part of a module you could use module augmentation to extend the interface:

//pModule.ts
export interface Params {
    messageId: number;
}

//pAug.ts
import { Params } from "./pModule";
declare module './pModule' {
    interface Params {
        nickname: string;
    }
}
//usage.ts
import {Params} from './pModule'
import './pAug'

let p : Params = {
    nickname: '',
    messageId: 0
}
Sign up to request clarification or add additional context in comments.

2 Comments

I see: the declaration merging on different files only works on module ?
If you use a module system, the interface will have to reside in a certain module which you have to import and then import the augmentations. You could also declare the interface in global declare global { export interface Params { messageId: number; } } and then the interface will be a global one and you can access it from any file (you ca import the files that contain the global declarations to bring them into scope)
0

Use generics:

export class Message<P extends Params> {
  constructor(
    public request: string,
    public params: P
  ) { }
}

export interface Params {
  messageId?: number
}

// profile-params.ts
export interface ProfileParams extends Params {
  nickname: string
}

const message = new Message<ProfileParams>('', { nickname: 'a' })

Comments

0

I don't fully know the reasons why right now (other than the fact that the moment something is exported it is turned into a module), but the only way I know how to accomplish this is to have them in their own individual files where nothing is exported and import the files (without the { Params } from syntax).

// ./message/params.model.ts
interface Params {
    messageId?: number;
}

// ./user/params.model.ts
interface Params {
    nickname: string;
}

// ./authorization/params.model.ts
interface Params {
    authorizations: string[];
}

// ./some.component.ts
import './message/params.model.ts';
import './user/params.model.ts';
import './authorization/params.model.ts';

const params: Params = {
    authorizations: ['black-belt', 'secret-service'],
    nickname: 'ninja',
    messageId: 1
};

1 Comment

Hi, thanks for your answer. I would have liked to not include every file like you did but I guess it makes more sense to do so

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.