microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.33k stars 12.54k forks source link

Optional Generic Arguments in Tuple #50473

Open tripolskypetr opened 2 years ago

tripolskypetr commented 2 years ago

⭐ Suggestion

Make support for optional generic arguments in tuple

type OptionalTuple<A = void, B = void, C = void> = [A, B, C]

const test: OptionalTuple = [ 1 ]; // should be casted to OptionalTuple<number>

πŸ“ƒ Motivating Example

I have the next JS code. It will type 1, 2, 3 into Chrome Dev Tools console output

const OptionalTuple = async ({ fetchState, children, }) => {
    const data = await Promise.all(await fetchState());
    return children(...data);
};

const App = () => {
    const fetchState = () => [
        Promise.resolve(1),
        Promise.resolve(2),
        Promise.resolve(3),
    ];
    return OptionalTuple({
        fetchState,
        children: console.log,
    });
};

App() // 1, 2, 3

I want to make It strictly typed to enable IntelliSense in VSCode. I tried, so I attach my last attempt below

declare namespace JSX {
    export type Element = any;
}

interface IOptionalTupleProps<A = void, B = void, C = void> {
    fetchState: () => Promise<[A, B, C]> | [A, B, C];
    children: (...data: [A, B, C]) => JSX.Element;
};

const OptionalTuple = async ({
    fetchState,
    children,
}: IOptionalTupleProps) => {
    const data = await Promise.all(await fetchState());
    return children(...data);
}

const App = () => {

    const fetchState = () => [
        Promise.resolve(1),
        Promise.resolve(2),
        Promise.resolve(3),
    ] as const;

    return OptionalTuple({
        fetchState,
//      ^^^^^^^^^^
//      The type 'readonly [Promise<number>, Promise<number>, Promise<number>]' is 'readonly' and cannot be assigned to the mutable type '[void, void, void]'    
        children: console.log,
    });
}

App();

But for now I am getting the following error. It looks like readonly [Promise<number>] can't be casted to [Promise<number>, void, void]

The type 'readonly [Promise<number>, Promise<number>, Promise<number>]' is 'readonly' and cannot be assigned to the mutable type '[void, void, void]'.

πŸ’» Use Cases

Optional tuple arguments can be used in React higher-order-components to enable powered type checking in functional programming

πŸ” Search Terms

βœ… Viability Checklist

My suggestion meets these guidelines:

tripolskypetr commented 2 years ago

TypeScript Playground link: https://www.typescriptlang.org/play?#code/CYUwxgNghgTiAEA7KBbEBnADlMCBSAygBrwDeAUPFfCAB6YD2MALvMwJ6YICiEIaiVgF54UROwDc5AL7lyAS0EgYAMxwIAkgHlMzeQ2QQAKgFdMfAAowGmdAB4AgvBEA3BvOAAaeACFn8Nw9vAGF-QOAAPjJKahUQZjAACwJmKGYQAC54AAoASmcoqwYUeXQQOwBtB28fEIBdKIAfeCqa+qlqeCT5CGA4RCzsgDoR4DSoLNbfevyhKMIiId5+EEEpaSlyMAN0Vh09AyhjMz5-KHR2RDAcik64hOTU9M8Yqm7e-pfpLO1dfUNTOYQEVbLMordqNtELt4GNUmcAO5QeSsIolMpDI4QbJQJEo+D3JIpNIgPK5DrUODMEwwRBdRI9PqrYajcbkmRyKEwhyYTD+PIFaKvLo7ViEx4k-lglrCzpo0ogIZwdAMCAuUkARlyL06cus6MVytV6uyACZtbLqPKMUa1aSAMwWzp1UToEXQ5ibTpUml0-b-I6AvjZCG6gnxIlPEA6sP0xn9LJc1WKiAMADmMao0nZsnIPMweSkQA

graphemecluster commented 2 years ago

Here you are: Link to playground​​

declare namespace JSX {
    export type Element = any;
}

interface IOptionalTupleProps<A, B, C> {
    fetchState: () => Promise<[A?, B?, C?]> | [A?, B?, C?];
    children: (...data: [A?, B?, C?]) => JSX.Element;
};

const OptionalTuple = async <A, B, C>({
    fetchState,
    children,
}: IOptionalTupleProps<A, B, C>) => {
    const data = await Promise.all(await fetchState());
    return children(...data);
}

const App = () => {

    const fetchState = () => Promise.all([
        Promise.resolve(1),
        Promise.resolve(2),
        Promise.resolve(3),
    ]);

    return OptionalTuple({
        fetchState,
        children: console.log,
    });
}

App();