DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Luke Harold Miles
Luke Harold Miles

Posted on • Updated on

Closest thing to structs / dataclasses / records in typescript with default values

(You may have also googled for

  • react typescript default props,
  • typescript default values for interface, or
  • typescript default destructured args.)

Data-only classes are easy to understand; you can add 'methods' (functions taking them) to them when you import them; there is no worries of using this wrong and it's usually easier to figure out if they are modified (partly because you can make a function argument const a bit more easily than with this); you know that they have a fixed set of attributes; methods and data are easily distinguishable. There's a reason structs fundamental in golang and something like structs has been added or always existed in python, swift, scala, etc.

So how do we do it in typescript? One mediocre option is to use regular classes and restrain yourself to avoid methods. I won't go into detail on that or other mediocre options that require repeating yourself three times. Below is a pretty good option, and now my go-to for structs in typescript.

Use a function to make your struct and Required<> for the exported type.

interface PartialCar {
    model: string
    owner: [string, string]
    year?: number
    make?: string
    staysNull?: string | null
}
export type Car = Required<PartialCar>
export function newCar(args: PartialCar): Car {
    return {
        year: 1999,
        make: "toyota",
        staysNull: null,
        ...args,
    }
}
export function print(c: Car): void {
    console.log(`${c.owner}'s gorgeous ${c.year} ${c.model} from ${c.make}`)
}
function example(a: number, b: number, c: Car): number {
    const c = newCar(pc)
    return a + b + c.year
}
function caller() {
    return example(5, 10, newCar({ model: 'ford', owner: ['bob', 'bill'] }))
}
Enter fullscreen mode Exit fullscreen mode

Ezpz. This also shows you how to do default/optional destructured parameters with thorough type hinting.

Edit: I realized a react example might be useful:

unction Car(props: {
    model: string
    owner: [string, string]
    year?: number
    make?: string
}): JSX.Element {
    const P = {
        year: 1999,
        make: "toyota",
        ...props
    }
    const length = P.make.length // passes strict null checks!
    return <div>
        {P.owner[0]} {P.owner[1]}{"'s"} {P.make} {P.model} goes vroom with {length} letters.
    </div>
}```



Using this in the codebase of splashcall rn.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)

Need better DEV posts?

You can set your approximate experience level in settings which can help improve the relevance of your DEV Home Feed.