Skip to content

infer the spread operator function parameter names and types, via generic type extraction #25634

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

Closed
wesleyolis opened this issue Jul 13, 2018 · 8 comments
Labels
Duplicate An existing issue was already created

Comments

@wesleyolis
Copy link

wesleyolis commented Jul 13, 2018

I would like the ability to be able to re-write and wrap code correctly for promises and similar things,
with out having to have a whole bunch of intermediate statements function calls, when could be done in one statement, but then I need the typing system to support the ability to be able to do that.

Their are 3 Features in this request, in priority order, were we can polyfill the rest with copy and past in the mean time.

  • infer the parameters for a spread operator.
  • Extract existing function parameter names and types with defaults
  • Conditional Generic extends constraint.
  • check the position of key in keyof (minor)

Extract Parameter Names And Types from a function

function MyFunc(a : string, b : boolean, ...args: A[]){}

type ExtractParamsNames<T extends Function> = 
{
	[K in keyof T] : K
}	

type funParamNames = ExtractParamsNames<typeof MyFunc>
// Exepect the following:
// a
// b
// ..args


type ExtractParamsTypes<T extends Function> = 
{
	[K in keyof T] : T[K]
}	

type funParamValues = ExtractParamsTypes<typeof MyFunc>
// Expect the following:
// string
// boolean
// A

type ExtractParamDefault<T extends Param> T extends {type: any, default : infer R} ? R : undefined

Conditional Generic extends constraint.

function fun<O extends {}, 
M extends keyof O ? keyof O :  O extends (A: infer, ..args: any []) => void ? A : undefined,
S extends O extends keyof O ? ExtractParms<O[M]> : DropPram<Extract<Params>>(paramA : O, paramB : M, args : S) : void

fun(object, 'key', EParamA, EParamB, EParamC); // this would be the typical way of doing tings.
fun(object.key,EParamA, EParamB, EParamC); // this  is why we need it, so I can drop a spread parameters and have the PropB become the first spread operator extracted parameter.

Extract types based on a key position

ExtractParamsWithPos<T extends Function> =
{
	[K in keyof T] : K extends T.Length ? {param: K, type: T[K]} : never
}

Infer the parameters of the spread operator

type CallBackType<T> =  (err: any, result:  T) => void

// Drop the call back function signature if found,
// need a way to determine if this is the last parameer as well.
ExtractParamsAndTypes<T extends Function> =
{
	[K in keyof T] : T[K] extends CallBackType ? never : {param: K, type: T[K]}
}


ExtractParamsAndTypesWithPos<T extends Function> =
{
	[K in keyof T] : K extends T.Length ? T[K] extends CallBackType ? never : {param: K, type: T[K]} : never
}

// like to be able to extract a functions types, using generics.
// the infer the current spread operate arguments, like in the following.

function Promisifiy<R, O, M extends keyof O | underfined,
A = ExtractParamsAndTypes<M extends undefined ? O : O[M]>
(obejct: O, keyMethod : M, ... args : A)
: R extends undefined ? ExtractBlueBirdCallbackResults<O[M]> : BlueBird<R> 
{
	if (propB === undefined)
			return Bluebird.promisify(propA)(args);
		else if (propA[propB])
			return Bluebird.promisify(propA[propB], {context: propA})(args);
// execute the statment, save me having to have intermediate step, 
// that is require to new the promise, can do all this in one line.
}


const lib = {
	myMethod : function (paramA : string, paramB : number, paramC : boolean, callback : CallBackType<Actually> ): void
}

Resulting use cases

Case A , when function signature is conventional/compliant for the types definitions.

interface Actually
{
	resultA : string,
	restultB  : number
}


const myMethodPromise = Promisify(lib, 'myMethod', 'paramA', 'paramB',' 'ParamC');
myMethodPromise.then(r => r.resultsA || r.resultsB);

Case B, Overide the return type

interface Overide
{
	OverideA : string,
	OverideB  : number
}

const myMethodPromiseOverideResult = Promisify<Overide>(lib, 'myMethod', 'paramA', 'paramB',' 'ParamC');
myMethodPromiseOverideResult.then(r => r.OverideA || r.OverideB);
@wesleyolis
Copy link
Author

wesleyolis commented Jul 13, 2018

Their is a small corner case now that I think of it for the following cases, were only paramA is used, then I need a way to differentiate be able to extracted params from a function base on their position, to be able to compute the overlap, by saying , there is ambiguity, if the first generic extracted param is a string and it matches that of first key, then their is a corner case that undefined type would need to be supplied for M. So basically the function signature becomes somthing like this.
In which case the M base type, needs to be able to evaluate

So this requires at least one more features request to fully work, that genric extends for M, be allowed to be evaluated conditions using extends to determine its type, I need to double check this fact.. never tried it before, if it works all great!

function Promisifiy<R, O, 
M extends keyof O ? keyof O : O extends (A: infer, ..args: any []) =>void? A : undefined,
A = ExtractParamsAndTypes<M extends keyof O ? O[K]] : DropFirstParam<O[K]>>
(obejct: O, keyMethod : M, ... args : A) :
: R extends undefined ? ExtractBlueBirdCallbackResults<O[M]> : BlueBird<R> 
{}

Type DropFirstParam<T extends Function> = T extends (paramA : any, args : infer R) => any? R : never 

cases

Case A , when function signature is conventional/compliant for the types definitions.

interface Actually
{
	resultA : string,
	restultB  : number
}

const myMethodPromise = Promisify(lib.myMethod, 'paramA', 'paramB',' 'ParamC');
myMethodPromise.then(r => r.resultsA || r.resultsB);

Case B, Overide the return type

interface Overide
{
	OverideA : string,
	OverideB  : number
}

const myMethodPromiseOverideResult = Promisify<Overide>(lib.myMethod, 'paramA', 'paramB',' 'ParamC');
myMethodPromiseOverideResult.then(r => r.OverideA || r.OverideB);

@mhegazy
Copy link
Contributor

mhegazy commented Jul 13, 2018

Part of this proposal is covered by #24897. We are working next on 1. enabling mapping on tuples/array types (today that is restricted to object types), and 2. adding higher order operators to spread and extract/infer types from tuples.

@mhegazy mhegazy added the Duplicate An existing issue was already created label Jul 13, 2018
@treybrisbane
Copy link

@mhegazy Are there issues tracking these that we can watch? A quick search on my part didn't find anything. :)

@wesleyolis
Copy link
Author

@mhegazy Hey, use search did return anything for me either. But I guess best that you guys, are able to have birds eye view of everything, which means, you just merge the posts, cause everyone has their own ideas and way to describe things. Still got 3 more bugs to log and features.. get to that to day, hopefully.

@wesleyolis
Copy link
Author

This is an additional feature request that builds on functionality here:
#25670

@wesleyolis
Copy link
Author

One could also look at writing the constraint in reverse, like in this post, however, their cons to that and advantages to being able to write the constraints in the forward direction.
#25670

@mhegazy
Copy link
Contributor

mhegazy commented Jul 16, 2018

Are there issues tracking these that we can watch? A quick search on my part didn't find anything. :)

not yet. we have discussed these as part of the tuples but have not logged anything yet.

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

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