Home > front end >  How can I force a string I provide to React props is of a certain type
How can I force a string I provide to React props is of a certain type

Time:01-18

I would like to provide a string to a prop in a react component coming from a library. But even though the library takes in any string, I want to make sure that the string I provide is of a certain type and if not I want typescript to provide me with an type error.

I would love something like the below, but where typescript would fail.

import React from "react";

// Can't modify this component or props
const ComponentFromLibrary: React.FC<{ str: string }> = ({ str }) => (
  <span>{str}</span>
);

// -----

type AllowedStrings = 'Hello'|'World'
export default () => (
  <div className="App">
    {/* This should not fail */}
    <ComponentFromLibrary str={"Hello" as AllowedStrings} />
    {/* This should fail */}
    <ComponentFromLibrary str={"world" as AllowedStrings} />
  </div>
);

example on codesandbox.io

CodePudding user response:

Wrap the library component in your own component that checks the type.

import React, {FC} from "react";

type AllowedStrings = 'Hello'|'World'

type Props = {
    str: AllowedStrings;
}
const ComponentFromLibraryWrapper:FC<Props> = ({str}) => <ComponentFromLibrary str={str} />

export default () => (
  <div className="App">
    {/* This should not fail */}
    <ComponentFromLibraryWrapper str="Hello" />
    {/* This should fail */}
    <ComponentFromLibraryWrapper str="world" />
  </div>
);

CodePudding user response:

I think typescript compiler is not working because of downcasting. Type AllowedStrings is overlaped by type string. This means downcasting is working and copiler understands "world" has type AllowedStrings. So using wrapper component is a solution you can choose.

import React from "react";

type AllowedStrings = "Hello" | "World";

const ComponentFromLibrary: React.FC<{ str: string }> = ({ str }) => {
  return <span>{str}</span>;
};

// Can't modify this component or props
const WrapperCompnent: React.FC<{ str: AllowedStrings }> = ({ str }) => (
  <ComponentFromLibrary str={str} />
);

// -----

export default () => (
  <div className="App">
    {/* This should not fail */}
    <WrapperCompnent str={"Hello"} />
    {/* This should fail */}
    <WrapperCompnent str={"world"} />
  </div>
);

CodePudding user response:

Maybe you could try using TS enum

enum AllowedStrings {
    Hello = "Hello",
    World = "World"
}

{/* Both works */}
<ComponentFromLibrary str={ AllowedStrings[ "Hello" ] } />
<ComponentFromLibrary str={ AllowedStrings[ "World" ] } />

{/* Both will throw error */}
{/* You can't use anything else instead those inside the enum */}
<ComponentFromLibrary str={ AllowedStrings[ "world" ] } />
<ComponentFromLibrary str={ AllowedStrings[ "anything else" ] } />

Here's a codesandbox example

Hope this helps :)

  • Related