Skip to content

Instantly share code, notes, and snippets.

@d-bucur
Last active September 20, 2023 15:40
Show Gist options
  • Select an option

  • Save d-bucur/c717d7fe0e78a635b7bf7960f48098e0 to your computer and use it in GitHub Desktop.

Select an option

Save d-bucur/c717d7fe0e78a635b7bf7960f48098e0 to your computer and use it in GitHub Desktop.
Using classes and type checks on objects to support typesafe dataclass like syntax, similar to Rust structs. Combining the best of classes with the best of objects at the cost of some type complexity

Playground link

class Person {
    firstName!: string; // required
    lastName!: string;  // required
    isAdult = true      // optional, has default

    // OPTION specify only required fields
    // constructor(params: Partial<Person> & Pick<Person, "firstName" | "lastName">) {
    // OPTION specify only optional fields
    // constructor(params: Omit<Person, "isAdult"> & Partial<Pick<Person, "isAdult">>) {
    // OPTION specify required and optional fields explicitly
    // constructor(params: Required<Pick<Person, "firstName" | "lastName">> & Partial<Pick<Person, "isAdult">>) {
    // OPTION using a cutom build type
    constructor(params: Dataclass<Person, "firstName" | "lastName">) {
        Object.assign(this, params)
    }

}
// we can also build custom types to simplify above constructors
type Dataclass<T, Required extends keyof T> = Partial<T> & Pick<T, Required>

let p = [
    // correct
    new Person({
        firstName: "Bob",
        lastName: "Dylan",
    }),
    new Person({
        firstName: "Bobby",
        lastName: "Dylan",
        isAdult: false,
    })
]

console.log(p)

// now we can use our favorite object syntax like spreading
let partialPerson = {
    firstName: "Bobby",
    isAdult: false,
}
let completePerson = new Person({
    lastName: "Dylan",
    ...partialPerson,
})

// following should always be wrong. required fields are not set
new Person({
    firstName: "Bob",
})

new Person({
})

new Person({
    firstName: "Bobby",
    lastName: undefined,
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment