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

Issues with getting the typings correctly #26252

Closed
pikax opened this issue Aug 7, 2018 · 5 comments
Closed

Issues with getting the typings correctly #26252

pikax opened this issue Aug 7, 2018 · 5 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@pikax
Copy link

pikax commented Aug 7, 2018

TypeScript Version: 3.1.0-dev.20180807

Search Terms:
Extend functions
Generic
Auto-complete
Template

Code

type MapFuncs<T, Key extends keyof T = keyof T> = { [K in Key]: Funcs<T[K]> };

type Funcs<T> = 
    T extends ()=> infer R ? R :
    T extends (...args: any[]) => infer R ? T : //  1 or more arguments 
    T;

interface PocFuncType {
    n: number,
    c: () => number;
    x:  (s: string) => number;
}

const f: MapFuncs<PocFuncType> = {} as any;

f.c; // returns number as expected
f.n; // returns number as expected
f.x; // return function as expected 

// is working as expected, but if we try to use it, it doesnt resolve the type correctly
type MyType<T> = {
    computed?: MapFuncs<T>
};

// factory
function create<T>(options?: MyType<T>){
    return null;
}

// it works we set the type
create<Partial<PocFuncType>>({
    computed: {
        c: 1,

        x(s) {
            if(!this.c){
                return 0
            }
            return this.c;
        },
    }
})

// it sets the {computed?: mapFuncs<any>}
create({
    // doesn't pick up the correct types, is setting as any
    computed:{
        data(){
            return 1;
        },
        dataReturn (){
            return this.data; // data is any, it should be number
        }

    }
})


create<Partial<PocFuncType>>({
    computed: {
        c: 1,

         x(s) {
            if(!this.c){
                return 0
            }
            return this.r; // invalid prop r, doesn't exist
        },
    }
})

Expected behavior:
this.data in dataReturn() should be interpreted as number based on the Funcs<T> type.

return this.r; should throw an error Cannot find name 'r'

Actual behavior:
this.data is interpreted different depending on the IDE (not sure if this is typescript compiler issue)

  • Playground : this is any
  • Visual Studio Code: this is resolve correctly but the props are all any making not as usefull
  • Webstorm: just ignores Funcs<T>

return this.r compiler doesn't complain about it, even if it doesn't exist on the type.

Playground Link:
playground

Related Issues:

@ghost
Copy link

ghost commented Aug 7, 2018

In a simplified test case:

type MapFuncs<T> = { [K in keyof T]: Funcs<T[K]> };
type Funcs<T> = T extends () => infer R ? R : T;

declare function create<T>(options?: MapFuncs<T>): T;

create({
    data() { return 1; },
    dataReturn() { return this.data * 2; },
});

What do you expect the inferred type argument for the create call to be? We can't use { data(): number, dataReturn(): number } because Funcs<T> will turn () => number into just number.

@pikax
Copy link
Author

pikax commented Aug 7, 2018

What do you expect the inferred type argument for the create call to be?
I expect Funcs<T> to convert the methods to be the result type if is a method without arguments: { data: number, dataReturn: number}

on the case of:

create({
    data() { return 1; },
    dataReturn() { return this.data * 2; },
    calculate(a: number, b: number){
      return a+b;
   }
});

// expect: { data: number, dataReturn: number, calculate: (a: number, b:number)=>number }

A practical example of this is VueJs when using Vue.extend(options?)

Other thing is the compiler doesn't throw error:

create({
    data() { return  this.empty; }, // empty doesn't exist nor is defined
});

@ghost
Copy link

ghost commented Aug 7, 2018

@pikax You probably don't have "strict": true set in your tsconfig, so this is allowed to be any.

Based on what you're saying it sounds like you have the parameter and return type reversed? You also need to set ThisType if this is the type of the returned object and not the type of the parameter object.

type MapFuncs<T> = { [K in keyof T]: Funcs<T[K]> };
type Funcs<T> = T extends () => infer R ? R : T;

declare function create<T>(options?: T & ThisType<MapFuncs<T>>): MapFuncs<T>;

const x = create({
    data() { return 1; },
    dataReturn(): number { return this.data * 2; },
});
x.data * x.dataReturn; // works

@pikax
Copy link
Author

pikax commented Aug 7, 2018

@pikax You probably don't have "strict": true set in your tsconfig, so this is allowed to be any.
Sorry, forget using tsc index.ts doesn't use the tsconfig

That seems to be work, thank you, is there any documentation for ThisType and other interfaces?

@pikax pikax closed this as completed Aug 7, 2018
@ghost
Copy link

ghost commented Aug 7, 2018

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Aug 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

2 participants