microsoft / microsoft/TypeScript
Idiomatic HKTs and Variadic Generic Types
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
Suggestion
Pertaining to the discussion in #1213 and having looked at similar suggestions (borrowing ideas where appropriate), this is a strawman proposal (syntax only) on HKTs and Variadic Generic Types that adheres to existing syntax and mindset in JS/TS , hence named "idiomatic".
🔍 Search Terms
HKT
Higher Order Types
Higher Kinded Types
Higher Order Type Functions
Higher Order Function Generic
Variadic Generic Types
✅ 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
Higher Kinded Types
Suggested syntax:
type HKT<S><T><V> = S<T<V>>;
Properties
- Positional clarity, same syntax for definition and invocation, visually similar to HOF calls:
f(x)(y)(z)
type WrappedArray<S><T> = S<T>[];
type ArrayOfPromises<T> = WrappedArray<Promise><T>;
// With a glance at the definition, we'll know that Promise is
// positionally assigned to S when invoked
- Spontaneous logic: more to the left => higher the kind (again similar to HOFs)
- Omission of lower kind = implicit inclusion
type ArrayOfAsyncIterables = WrappedArray<AsyncIterable>;
// == type ArrayOfAsyncIterables<T> = WrappedArray<AsyncIterable><T>;
Variadic Generic Types
Suggested syntax:
function aFunction<...T>(...args) {
return anotherFunction<...T>(...args);
}
Properties
- Reuses spread operator, same as in Variadic Tuple Types, exact match with how parameters are spread in JS
- Paves the way for generic inference
type Generics<F extends (...args) => any> = F extends <...infer G>(...args) => any
? G
: never;
📃 Motivating Example
I was looking at the code in the streaming-iterables package, the pattern of defining an _fn and then overloading it with an fn including a curried version seems a case of DRY, happens in all functions the package exposes.
Below code was my attempt at a general currying overload implementation for the package:
type Leading<T extends any[]> = T extends [...infer I, infer _] ? I : never;
type Last<T extends any[]> = T extends [...infer _, infer I] ? I : never;
function curried<F extends (...args) => any>(
fn: F
): {
(...args: Parameters<F>): ReturnType<F>;
(...args: Leading<Parameters<F>>): (curried: Last<Parameters<F>>) => ReturnType<F>;
} {
return (...args) =>
args.length == fn.length - 1
? curried => fn(...[...args, curried])
: fn(...args);
}
This works well until generics come into play:
function a<T>(b: string, c: number, d: T[]) {
return [b, c, ...d];
}
const f = curried(a);
f('hi', 42, [1, 2, 3]) // d: unknown[], expected: number[]
f('hi', 42) // curried: unknown[], expected: T[]
💻 Use Cases
Using this proposal, the example described in the previous section can be covered:
function curried<F extends (...args) => any>(
fn: F
): {
<...T extends Generics<F>>(...args: Parameters<F><...T>): ReturnType<F><...T>;
<...T extends Generics<F>>(...args: Leading<Parameters<F><...T>>):
(curried: Last<Parameters<F><...T>>) => ReturnType<F><...T>;
} {
return // same as before
}
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Non vengono indicati file di implementazione, punti di ingresso o test. Inizia esaminando la discussione in #1213 e i suggerimenti collegati sugli Higher-Kinded Types, quindi determina se la sintassi proposta per HKT e i generics variadici è compatibile con il design del sistema dei tipi. Per considerarlo completato sarebbero necessari un design accettato e modifiche al compilatore e ai test, ma l’issue non definisce tali posizioni.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Da chiarire
- Idoneità per principianti
- 15/100