mleister
mleister

Reputation: 2585

Loosing type-information by exporting constant as an object

The following approach (exporing a object) hints an error:

types.ts

interface SetAppDataAction {
    type: typeof SET_APP_DATA // need to be exactly the string! not just any string
}

const SET_APP_DATA = "SET_APP_DATA"
export default { SET_APP_DATA }

action.ts

import types from "./types";

const setAppData = (appData: IAppDataState): SetAppDataAction => {
    return {
        type: types.SET_APP_DATA, // Typescript error: TS2322: Type '{ SET_APP_DATA: string; }' is not assignable to type '"SET_APP_DATA"'
        payload: appData
    }
}

Can anyone explain me whats going on here? Is it possible that the type information is lost by wrapping it in a object? (type before: exactly "SET_APP_DATA", afterwards only string?)

enter image description here

Upvotes: 1

Views: 737

Answers (2)

Bergi
Bergi

Reputation: 665121

Yes, this is normal. Putting constants in objects makes the (mutable!) object property have a less specific type. You can prevent this using const assertions:

export default { SET_APP_DATA } as const;

However, I would recommend that you do not default-export an object at all! Rather make use of names exports:

// types.ts
export const SET_APP_DATA = "SET_APP_DATA";
// action.ts
import * as types from "./types";

const setAppData = (appData: IAppDataState): SetAppDataAction => {
    return {
        type: types.SET_APP_DATA,
        payload: appData
    }
}

Upvotes: 3

Antoine Eskaros
Antoine Eskaros

Reputation: 851

Another solution would be to use explicit typing instead of relying on type inference.

interface SetAppDataAction {
    type: typeof SET_APP_DATA // need to be exactly the string! not just any string
}

const SET_APP_DATA = "SET_APP_DATA"
const objectToExport: { SET_APP_DATA: typeof SET_APP_DATA } =  { SET_APP_DATA }
export default objectToExport

Upvotes: 1

Related Questions