'Why is the inferred type like this ?

example

function Component<TProperty, TData extends (prop: TProperty) => Record<string, any>, TComputed extends { [k: string]: (data: TProperty & (TData extends ((prop: any) => infer R) ? R : never)) => any }>
(opt: { properties: TProperty, data: TData, computed: TComputed })
: TData { return '' as any }

const test1 = Component({
    properties: { propA: '' },
    data: () => { return { dataA: '' } }, 
    computed: {
        ccc(AllData) {                         // this AllData of type  is  {propA:string} & {dataA: string}                  
            return AllData.propA  
        }
    }
})

const test2 = Component({
    properties: { propA: ''},
    data: (prop) => { return { dataA: '' } }, // Add parameters "prop"     In order to be usable  {dataX:prop.xxx}
    computed: {
        ccc(AllData) {                      // this Alldata of type  is {propA:string} & Record<string, any>      why???
            return AllData.propA
        }
    }
})

[playground]https://www.typescriptlang.org/play?#code/LAKFDMFcDsGMBcCWB7aACAwsgtgB1QKbTwA8AKgAoBOyuBV8AngDRpkAiAhvJ2gQB7wiAEwDOaABS4auAFxtqtekwCUaALwA+NACUCsZFWElR8KomgBzVp2iNNrMljyQhwvoJHiA3mgDaANbypuZWALryEsLcnPKUMsqMaABkkhwxHkLQYpJSMvK2jGpaaBbg9LpqAPy6aPLQBABu9CrF2oVoAL6aoGh9krTw8r7SSgyIBKJxinQMLGjRPHFcPKwGLm5xzriuBO6dKr39yxm+VATwkFToAOQ3aJziHZ2goAbQpmhCpgCMGpg4fANYgSbxHPqjWZISbDNCQgCC8juXWY4IWMUibTQZwuV3QvkWnERaGRnRRaDR6x2m2xaP6aFgjIk8IANiyVpw1L56TzeXy+gB6AVfAAWiCebI5aGQ4C+jDofXFfW8CNkIQsljJqW8hOJ6qsZP5RrpfPOl2uaFZ7JiADoEX0TX0XiB6c6Dq8QO9Pt94AAmf7bQggsEu-qQ5QTKbYuEyYl3Tqo0N9QmRSFYnHm-Honhx+5khNoIWW4TuXCcKicbAXejiABEkNrPIAkuhDMIKvBkGgAEYENCQUScbssvvYwkADVkkJt-FnzvpVN2wmGjoZTKtHK5Ru3-SL8DF4ithOlsqYCtKPlV+s1KV0+jbJjMGpsdm0PIA7iLGFUf6v6Wa8UtSVbQRVd536N1DjAEAgA



Solution 1:[1]

This is a design limitation of TypeScript; see microsoft/TypeScript#38872 for a canonical answer, especially this comment. In the test2 example, you are essentially asking the compiler to infer the generic type parameters TProperty, TData, and TComputed and contextually infer the types of the callback parameters in the data and computed properties. Such inference happens in a limited number of phases where first the compiler plugs in wildcard/default values for some of the unknown types to infer others, and then it uses those inferences to inform the next round. Unfortunately, it is unable to infer all the types you need before it stops, and so some of the type positions still have their default values (like Record<string, any>, the constraint for the return type of TData).

In cases like this, you usually have to give up some inference in favor of some manually specified or annotated types. In your test1 example, the data callback parameter is missing and therefore no longer contextually typed. If you want something like test2 to succeed, you can free the compiler from contextually typing the parameter by annotating it explicitly:

const test3 = Component({
    properties: { propA: '' },
    data: (prop: { propA: string }) => { return { dataA: '' } },
    computed: {
        ccc(AllData) {                      
            return AllData.propA
        }
    }
})

And if you inspect that, you'll see that AllData has type { propA: string; } & { dataA: string; } as desired.

Playground link to code

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1