farts and crafts
farts and crafts

Reputation: 3

Need help parsing TypeScript syntax

I'm new to TypeScript and can't mentally parse its syntax -- I'm a backend engineer, so I don't spend much time with JavaScript/JavaScripty-languages. I've tried searching, but I can't find anything that details what I'm seeing (and because I'm new to the language, I'm probably not using the correct terms).

In the following code, what am I looking at?

/**
 * `makeStyles` where the passed `styles` do not depend on props
 */
export default function makeStyles<Theme = DefaultTheme, ClassKey extends string = string>(
  style: Styles<Theme, {}, ClassKey>,
  options?: Omit<WithStylesOptions<Theme>, 'withTheme'>
): (props?: any) => ClassNameMap<ClassKey>;

https://github.com/mui-org/material-ui/blob/9bd4277ecd660ebe2fd4cb08960f58e98ddb6d43/packages/material-ui-styles/src/makeStyles/makeStyles.d.ts

I understand the export default function funcName, but after that I'm less sure. This is what my brain sees:

// default named export for renaming hijinks
export default function

// function name, type annotated argument list?
makeStyles<Theme = DefaultTheme, ClassKey extends string = string> 
(
  // property being passed to property name with typed annotation on argument?
  style: Styles<Theme, {}, ClassKey>,

  // 'options' are optional in the interface, so when passing this argument we also have to include '?' ?
  options?: Omit<WithStylesOptions<Theme>, 'withTheme'>
// if there are any 'props' (which are optional in the interface), we bind as props on the return type of 'ClassNameMap'
): (props?: any) => ClassNameMap<ClassKey>;

but that's probably wrong. Can you help me understand the components or help with the vocabulary needed to learn?

Upvotes: 0

Views: 211

Answers (2)

Pradeep Dayaram
Pradeep Dayaram

Reputation: 226

It is a lot to unpack, here it is line by line.

export default function

Your spot on about this line. Just exporting the function to make it available elsewhere in the program.

makeStyles<Theme = DefaultTheme, ClassKey extends string = string>

Here makeStyles is the name of the function.

What's in between the <> is the generic arguments that it takes. Typescript Generics let you write functions that can take a variety of types as arguments. For example:

function identity<T>(arg: T): T {
    return arg;
}

The argument here is arg: T, which means arg must be of type T, and the return is typed with (): T, this second :T after the closing bracket indicates the return type of the function. So the argument and the return of this function must be of the same type.

So in our example the makeStyles function takes a generic argument of Theme and ClassKey. Generics also let you specify default values for these arguments if they aren't explicitly passed in. So where you see:

<Theme = DefaultTheme, ClassKey extends string = string>

If the values are not defined when the function is invoked, then Theme will be of type DefaultTheme, and ClassKey will be of type string.

The other piece there is that ClassKey extends string. That just means that it inherits all the string properties within it's type.

Then we have the arguments themselves here:

(
  style: Styles<Theme, {}, ClassKey>,
  options?: Omit<WithStylesOptions<Theme>, 'withTheme'>
)

style is the first argument. It's of type Styles which is also a generic type that takes three arguments. You may want to look up the Styles interface or type to see what that looks like to get more clarification. Here is an example of what it could look like:

interface Styles<ThemeType, AppType, ClassKeyType> {
     theme: ThemeType;
     app: AppType;
     classKey: ClassKeyType;
     .... a bunch of other properties for the styles type.
}

With Generics you can pass in a variety of types, which makes things more flexible. And the typescript compiler is smart enough to enforce this within your code depending on how things were invoked or instantiated.

options is the second argument. You are correct about the ?, that signifies that it is an optional argument. If it is not passed in, it will just be undefined. Here we are using a special typescript type called Omit. Omit will take a type as it's first argument, and a key of that type as the second argument. It will return a new type that has all the properties of the original type you passed in as the first argument, EXCEPT, the key that you passed in as the second argument.

Here WithStyleOptions is another generic type, like styles. It takes Theme as it's argument. From there Omit will take that type, and produce a new type, and exclude the withTheme property.

Then we have:

: (props?: any) => ClassNameMap<ClassKey>;

This last piece is typing the return type of the function. In this case, this function will return another function.

The new function it returns will take one argument named props which will have a type of any. any in typescript means what you would think, it could literally be anything. This function will have a return type of ClassNameMap, which is another generic.

For sure take a look at all the generics you are using here, and see how they are defined. That should help. Also see where the makeStyle function is called, I think seeing it from the other side will also be helpful.

Upvotes: 2

dwmorrin
dwmorrin

Reputation: 2734

This is just a type defintion (everything in the .d.ts file should just be definitions). Everything is typing.

The angle brackets <> after the function name indicate it is a generic function, which means you can specify a specifically typed instance of makeStyles. The = is for providing default types.

Next is the parameters, surrounded by (). These are just named parameters with their type annotations. Yes, ? indicates the parameter is optional. Omit is a utility type that will drop the specified key from the type.

The : after the parentheses is for the return type. In this case, this function returns a function. The syntax for returning a function is (parameter: parameterType) => returnType.

// default named export
export default function

// generic function with default types
makeStyles<Theme = DefaultTheme, ClassKey extends string = string> 
(
  // parameter with typed annotation
  style: Styles<Theme, {}, ClassKey>,

  // option parameter, Omit is a TypeScript global utility,
  // takes everything but 'withTheme' from WIthStylesOptions<Theme>
  options?: Omit<WithStylesOptions<Theme>, 'withTheme'>
// returns a function that takes props and returns a ClassNameMap<ClassKey>
): (props?: any) => ClassNameMap<ClassKey>;

Upvotes: 0

Related Questions