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>
);
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 :)