Skip to content

Document TypeScript soundness (or unsoundness) intentions #1546

@jedwards1211

Description

@jedwards1211

Various object functions in es-toolkit (and probably originally lodash DefinitelyTyped defs) are unsound. This may be intentional, but I don't see any documentation of whether it's intentional or not, or any general warnings about errors that could result, so I don't know if you've thought about it.

For example:

import { mapValues } from 'es-toolkit/object'


function unsound(obj: { a: number }) {
  return mapValues(obj, (x) => x.toFixed(2)) // 💥 crashes on `b: true` property below
}

const x = { a: 1, b: true }
unsound(x) // No TS errors, but crashes 😬

This is similar to how TS chose to make Object.keys() soundly return string[], but accidentally accepted a contradictory change that allows Object.values() to unsoundly return T[keyof T][] instead of unknown[]. There's a lot of debate over how the contradiction should be resolved.

If soundness is preferrable you could declare the getNewValue type as

getNewValue: (value: SoundValueOf<T>, key: string, object: T) => V

Where

type SoundValueOf<T> = string extends keyof T ? T[keyof T] : unknown

This would catch the issue above at compile time, and wouldn't cause any new errors for objects where the key type is any string (hopefully the most common case for iterating an object?) But it would cause new errors if the key type is narrower than string.

If the types are intended to be pragmatic then it wouldn't hurt to explain that there could be unexpected errors if an object has additional properties not anticipated by the type literal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions