Default value for typescript type alias
Asked Answered
K

6

51

Can typescript type alias support default arguments? For instance:

export type SomeType = {
    typename: string;
    strength: number;
    radius: number;
    some_func: Function;
    some_other_stat: number = 8; // <-- This doesn't work
}

The error is A type literal property cannot have an initializer.

I can't find documentation relating to this - type keyword is very obscure behind everything else that is also named type. Is there anything I can do to have default argument value for type in typescript?

Kenney answered 18/5, 2020 at 4:0 Comment(1)
Haha! a very C# dev questionEuphony
Q
54

You cannot add default values directly to a type declaration.

You can do something like this instead:

// Declare the type
export type SomeType = {
    typename: string;
    strength: number;
    radius: number;
    some_func: Function;
    some_other_stat: number;
}

// Create an object with all the necessary defaults
const defaultSomeType = {
    some_other_stat: 8
}

// Inject default values into your variable using spread operator.
const someTypeVariable: SomeType = {
  ...defaultSomeType,
  typename: 'name',
  strength: 5,
  radius: 2,
  some_func: () => {}
}
Querist answered 18/5, 2020 at 4:22 Comment(2)
And how do you do this when someTypeVariable is injected into a function?Demonstrative
@Demonstrative you can extract function parameters (see "Unpacking properties from objects passed as a function parameter") and give them default values directly. If you are confused, please, make a new question and tag me.Manure
D
18

Type does not exist in runtime, so a default value makes no sense. If you want to have a default default, you must use something that exists in runtime, such as a class or a factory function

Delphinus answered 18/5, 2020 at 8:18 Comment(0)
B
2

Not possible with TypeScript.

If you simply want to document the default, then you need JSDoc:

/**
 * @typedef {object} SomeType
 * Description of what SomeType is.
 * @property {string} typename - Description of this property.
 * @property {number} strength - Description of this property.
 * ...
 * @property {string} [some_other_stat=8] - Description of this property.
 */
export type SomeType = {
    typename: string;
    strength: number;
    radius: number;
    some_func: Function;
    some_other_stat: number;
}

If you are trying to actually set a default value, then it has to be done with real JavaScript:

// It all kind of depends on the use case, but here's some ideas.
// When initializing...
someType.some_other_stat = stat ??= 8;

// Or perhaps this happens in a function...
function getSomeType(stat: number = 8): SomeType {
  return {some_other_stat = stat, <otherProperties>};
}

// Or in a constructor...
class SomeType {
  constructor(some_other_stat = 8) {
    this.some_other_stat = some_other_stat;
    ...
  }
}

// When reading...
const {some_other_stat = 8} = someType;

// Or...
const otherStat = someType.some_other_stat ??= 8

I find cases like this all the time where I question why we bother with TS in the first place.

Bergen answered 21/8, 2023 at 16:16 Comment(0)
M
1

You can't add default values directly to type.

I would suggest the following instead

type Person = {
    name: string
    age?: number // Add '?' such that Pick allows you to skip the field (i.e. not force to set))
    country?: string
    readonly createTime: string
    Say(msg: string): string
}

function NewPerson(name: string, options?: Pick<Person, "country" | "age">): Person {
    const createTime = new Date().toISOString() // Here you can set the default value
    const defaults = {
        createTime,
        Say(msg: string): string { // Implement the method
            return msg
        }
    }
    return {
        name,
        ...options,
        ...defaults,
    }
}

const carson = NewPerson("Carson", {age:30})
console.log(carson.name)
console.log(carson.createTime)
console.log(carson.Say("hello world"))
const bar = NewPerson("Bar")
console.log(bar)

playground

Monstrous answered 20/9, 2022 at 7:24 Comment(0)
R
0

The challenge is that TypeScript’s types only exist at compile time, and all type information is erased after compiling (with a few exceptions like enum). Therefore, there’s no way to change runtime behavior based on type information.

To the best of my knowledge, there are no bundler plugins that can automatically generate default values for TypeScript types as well. One challenge is that TypeScript uses structural typing, which means it cannot distinguish between types that have the same structure. If two types have the same structure but different use cases requiring different default values, it would be impossible to generate distinct default values for each, even with a bundler plugin.

If you have experience with programming languages like Java and Rust, you might notice a similar pattern where an interface or trait is implemented by a class or struct to enable certain functionalities, like the Comparable interface in Java or the Default trait in Rust.

You can simulate this in JavaScript by moving the “interface implementation” to an object and manually passing this object (the “externally defined interface implementation”) to a function that needs it. The following example demonstrates this, similar to how “Type classes” are used in fp-ts:

interface Default<T> {
  default: T;
}
const getDefault = <T>(d: Default<T>): T => d.default;

const defaultString: Default<string> = {
  default: "",
};
const defaultNumber: Default<number> = {
  default: 0,
};

interface Point {
  x: number;
  y: number;
}

const defaultPoint: Default<Point> = {
  default: { x: getDefault(defaultNumber), y: getDefault(defaultNumber) },
};

interface Vector {
  from: Point;
  to: Point;
}

const defaultVector: Default<Vector> = {
  default: { from: getDefault(defaultPoint), to: getDefault(defaultPoint) },
};

// ...Somewhere else in the code, such as in React
const [data, setData] = useState({ v1: getDefault(defaultVector), v2: getDefault(defaultVector) });

It might seem odd to use a Default<T> instead of just T as the “implementation of a Type class”. In this case, it might not make much sense, but if you want to define more “Type classes” that hold more than one property, such as Monoid in fp-ts, this paradigm becomes more consistent and universal.

Raising answered 3/7 at 6:5 Comment(0)
J
-2

You can do something like this when calling the function:

// A function with a default parameter
function sayHello(name = "stranger") {
  console.log(`Hello, ${name}!`);
}

// We can call the function with or without an argument
sayHello("Alice"); // Hello, Alice!
sayHello(); // Hello, stranger!

Reference

Jemie answered 31/1 at 6:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.