I have the disgusting code below where I want to combine the safety of TypeScript typing and default values of a variable:
interface Store {
infinoteToken: string | null,
allNotes: Note[],
// plenty more
}
export const store: Store = reactive({
infinoteToken: null,
allNotes: [],
// plenty more
})
I end up with two blocks of code with duplicated information.
Is there a way to combine these two elements to declare an Object with default values and types for its members?
CodePudding user response:
This all can be moved to a class with default implementation:
class Store {
infinoteToken: string | null = null;
allNotes: Note[] = [];
// plenty more
}
export const store = reactive(new Store());
CodePudding user response:
You can declare your object of defaults and then derive the type from it:
const STORE_DEFAULTS = {
infinoteToken: null as string | null,
allNotes: [] as Note[],
numericProperty: 1,
booleanProperty: true,
// plenty more
}
interface OptionalStoreProperties {
optionalString?: string;
// potentially more
}
type Store = typeof STORE_DEFAULTS & OptionalStoreProperties ;
- Simple properties like
numericProperty
andbooleanProperty
that match the type of the default value will be inferred correctly. - You have to use a type assertion to override the type if it is not the same as the value you assign:
infinoteToken
can benull
or string, so theas string | null
makes sure strings are still assignable to it. - Empty arrays also always need to be type asserted. Otherwise
allNotes
will default tonever[]
. - If there are optional properties that should not be initialised, then you need to add them to the type. A type intersection (
&
) (link is to the old TypeScript Hanbook because the new one does not include an explanation of intersections. The old information is still relevant) will combine the properties of the two types.
With that said, I would suggest keeping the type and defaults separate. It may look like repeated code but it hardly is.
- It is clearer to understand type by looking at only that information, rather than having to mentally separate which property is of which type (assuming implicit assignments.
- It is also clearer what the defaults are when they are separate from all the other code.
- If you add comments about different things it is clearer what you refer to. Maybe you want to say why a given default was chosen. Or maybe you want to explain how a property is to be used. These need not be in the same place.
- You can also have multiple default values. Maybe not for this type but it is definitely possible to decide on defaults based on some condition and apply only those. Keeping type and sets of defaults separate keeps this option open and easier to expand with more.