0

My question is about my update method. As you can see below, it can receive an object(newState), and updates the class instance properties using Object.assign(). I need to tell TS that it should only accept:

  • An object
  • Properties that are keys of the State Class
  • Values of those properties that are proper types of the properties.

Did I type this method correctly? Is there a better//other way to do it?

Also, in main.ts, on the State class implements StateInterface, the TS compiler has an error that the parameter for update (newState) is implicitly any. Shouldn't it be receiving the type information from types.d.ts?:

/// types.d.ts
export interface StateInterface {
    user: User;
    fileList: DirectoryResponse;
    selectedFiles: Array<SelectedFile>;
    currentDir: string;
    response: APIResponse;
    menu: Menu;
    dialog: Dialog;
    history: object;
    update: <P extends StateInterface, T extends keyof StateInterface>(newState: { [key in T]: P[T]}) =>
                                                                                            Promise<void>;
    syncPage: () => void;
}

/// main.ts
class State implements StateInterface {
    user: User;
    fileList: DirectoryResponse;
    selectedFiles: SelectedFiles;
    currentDir: string;
    response: APIResponse;
    menu: Menu;
    dialog: Dialog;
    history: History;

    constructor(user: User, fileList: DirectoryResponse, selected: SelectedFiles, currentDir: string, response: APIResponse, menu: Menu, dialog: Dialog, history: History = { forward: false, back: false }) {
        this.user = user;
        this.fileList = fileList;
        this.selectedFiles = selected.slice();
        this.currentDir = currentDir;
        this.response = response || { fileResults: [], folderResults: [] };
        this.menu = menu || { location: '', type: 'folder' };
        this.dialog = dialog || { type: "", state: false };
        this.history = history;
        }

        get dir() {
            return this.currentDir.slice(1).split('/');
        };

        async update(newState): Promise<void> {
                     ^^^^^^^^ (implicit any)
            if (newState) {
                Object.assign(this, newState);
            } 
            
            this.fileList = await readDir(this.currentDir).then(r=>r.json());
        }
}
Jordan
  • 194
  • 1
  • 12

1 Answers1

1

The way you typed StateInterface suggests you only want keys of StateInterface in the newState (and not other properties possibly existing in State).

If this is the case, I would type update in both interface and class as

update(newState: Partial<StateInterface>): void {
  ...
}

Also note that this allows functions existing in the StateInterface to be replaced, younprobably want to use Omit to get rid of unwanted keys.

Lesiak
  • 22,088
  • 2
  • 41
  • 65
  • Yes, I only want keys of StateInterface to be updated. I don't want someone adding a random extra key onto the class instance. I will take a look into Omit, thanks! – Jordan Jan 14 '21 at 15:45
  • 1
    Note that this is only compile-time check, if your newState conforms to Partial but also has some extra properties in runtime, the extra properties will be copied (which may or may not be a problem, depending on your use case) – Lesiak Jan 14 '21 at 18:19