Sam Chung
Sam Chung

Reputation: 65

TypeScript return exact function infer type

I have this function:

const plainText = (text: string) => ({
  type: 'plain_text',
  text,
  emoji: true,
});

At the moment the inferred type return is:

const plainText: (text: string) => {
    type: string;
    text: string;
    emoji: boolean;
}

Is there a way to make it return like this with the type of type being 'plain_text' as opposed to string? Or do I need to manually declare the return type?

const plainText: (text: string) => {
    type: 'plain_text';
    text: string;
    emoji: boolean;
}

I found I can do the following, but is this the best way to do it?

const plainText = (text: string) => ({
  type: 'plain_text' as 'plain_text',
  text,
  emoji: true,
});

I've got others like this:

const text = (text: string) => ({
  type: 'section',
  text: {
    type: 'mrkdwn',
    text,
  },
});

I'm trying to just create a bunch of functions to represent some repeated basic Slack Block types that I'm using so I can just pass them with eg. plainText('hello'). As I won't need to configure them, everything remains static and only the text changes.

The problem is when I call it against a Slack Client it required the typing to be exactly type: 'plain_text' instead of type: 'string'. Type definition

Upvotes: 2

Views: 518

Answers (3)

Linda Paiste
Linda Paiste

Reputation: 42188

The problem is when I call it against a Slack Client it required the typing to be exactly type: 'plain_text' instead of type: 'string'. Type definition

You can declare a specific return type for your function rather than letting it be inferred. My recommendation is that you make use of the types which are already defined by Slack when you are making factories for them.

import {PlainTextElement} from "@slack/types";

const plainText = (text: string): PlainTextElement => ({
  type: 'plain_text',
  text,
  emoji: true,
});

Upvotes: 2

cdimitroulas
cdimitroulas

Reputation: 2539

If you just want the type property to be the string literal, then you can use as const on that property to force typescript to treat it as the literal string "plain_text" rather than a generic string type:

const plainText = (text: string) => ({
  type: 'plain_text' as const,
  text,
  emoji: true,
});

What you did with 'plain_text' as 'plain_text' is also fine though! They are equivalent.

Upvotes: 2

Just use generics:

const plainText = <T extends string>(text: T) => ({
  type: 'plain_text',
  text,
  emoji: true,
}) as const; // small update

const foo = plainText('hello')

Playground

In above case, TS will try to infer the type of argument.

Upvotes: 0

Related Questions