Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable local type bindings with type definitions #48394

Closed
5 tasks done
tshelburne opened this issue Mar 23, 2022 · 2 comments
Closed
5 tasks done

Enable local type bindings with type definitions #48394

tshelburne opened this issue Mar 23, 2022 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@tshelburne
Copy link

Suggestion

πŸ” Search Terms

"type internal definition" "where" "where clause" "local variable" "local binding"

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

For particularly complicated type definitions (eg. large, complex unions), I would like to add a way to create locally bound types that are scoped only to that type definition. These would compile away along with the type itself, and are purely to enable local abstractions for legibility and "DRY"ness.

πŸ“ƒ Motivating Example

As type definitions get more complicated, they tend to become less legible and more difficult to maintain. A significant part of the struggle comes from not having a syntactic tool to create abstractions within the context of the type itself.

πŸ’» Use Cases

The sample below is a greatly simplified example of some props definitions I use in a table column type. In the example, we have an item type T, a value type V, and a set of keys which are valid for filtering (F) and sorting (S).

In the "explicit" version, both logic and code are duplicated in the type definition.

type KeysOfType<T, V> = keyof {
    [K in keyof T as T[K] extends V ? K : never]: any
}

type ExplicitColumn<T, V, F extends string, S extends string> =
    | { value: F & S & KeysOfType<T, V> }
    | { value: (v: T) => V, k: F & S & KeysOfType<T, V> }
    | { 
        value: (v: T) => V
        filterBy?: F & KeysOfType<T, V>
        sortBy?: S & KeysOfType<T, V>
    }

In the readable version, I've extracted a "global" helper type to make the overall type a bit more legible. While this does work and makes it more legible, we're forced to copy and paste strings of generic arguments that obscure the intention and risk unnecessary C&P mistakes. Additionally, "global" types need to be named more verbosely to keep clarity maximalized.

type LimitToKeysOfValueType<T, V, K> = K & KeysOfType<T, V>

type ReadableColumn<T, V, F extends string, S extends string> =
    | { value: LimitToKeysOfValueType<T, V, F & S> }
    | { value: (v: T) => V, k: LimitToKeysOfValueType<T, V, F & S> }
    | {
        value: (v: T) => V
        filterBy?: LimitToKeysOfValueType<T, V, F>
        sortBy?: LimitToKeysOfValueType<T, V, S>
    }

The ideal type is my proposal - it improves legibility and discourages copy and paste, instead relying on locally bound type helpers. I don't have a strong opinion about the keyword / syntax to actually enable the feature (I'm using where as inspired by Haskell where expressions), though I do think having the syntax be supported as a postfix to the type definition is significant, as it encourages taking in the type as a whole rather than the component implementations.

type IdealColumn<T, V, F extends string, S extends string> =
    | { value: ComboK }
    | { value: (v: T) => V, k: ComboK }
    | {
        value: (v: T) => V
        filterBy?: Limit<F>
        sortBy?: Limit<S>
    }
    where
        type ComboK = Limit<F & S>
        type Limit<K> = K & KeysOfType<T, V, K>
@MartinJohns
Copy link
Contributor

Duplicate of #41470.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 28, 2022
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants