Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript extend type if boolean type is true

I'd like to know if it's possible to extend a type depending on another type's value?

interface NavType {
    hideNav?: boolean
    dev?: boolean
}

I'd like to allow the use of hideNav only if the dev arg is false.

const Navbar: React.FC<NavType> = ({ children, hideNav, dev = false }) => (
    <nav>
        {!dev ? (
            <NavDefault hideNav={!!hideNav}>{children}</NavDefault>
        ) : (
            <NavDev>{children}</NavDev>
        )}
    </nav>
)

How can I use conditionals in this case?

// Should PASS
const navArgs1: NavType = {
    hideNav: undefined,
    dev: true
}

const navArgs2: NavType = {
    hideNav: true or false,
    dev: false
}

// Should NOT PASS
const navArgs3: NavType = {
    hideNav: true or false,
    dev: true
}
like image 263
Hiroyuki Nuri Avatar asked Dec 21 '21 09:12

Hiroyuki Nuri


People also ask

Can you extend a type in TypeScript?

To extend types in TypeScript, we can use the extends keyword. to create the UserEvent interface that extends the Event type. We extend it by adding the string UserId field in UserEvent and inheriting the rest from Event .

How do you add a condition in TypeScript?

Syntax: We can create the conditional types with the used of ternary operator and extends in TypeScript. Type1 extends Type2 ? for One value : for different value; Here extend works as compare function which checks is Type1 have properties of Type2 if yes then it jumps to true branch else in the false branch.

What is ?: In TypeScript?

What does ?: mean in TypeScript? Using a question mark followed by a colon ( ?: ) means a property is optional. That said, a property can either have a value based on the type defined or its value can be undefined .


Video Answer


1 Answers

You can define 2 types and let the component properties be their union; in principle the following (shown as TS Playground code):

interface NavBase {
    dev: boolean;
}

interface DevNavType extends NavBase {
    dev: true;
    hideNav?: undefined;
}

interface NotDevNavType extends NavBase {
    dev: false;
    hideNav: boolean;
}

// This simulates your component
function f(x: DevNavType | NotDevNavType) {

}

f({ dev: true });                      // Works
f({ dev: true, hideNav: undefined });  // Also works
f({ dev: false, hideNav: true });      // Works too - for any boolean value of hideNav
f({ dev: false });                     // Compiler error
f({ dev: true, hideNav: true });       // Compiler error

Notes:

  1. You don't really need the base interface, NavBase
  2. You may want to define a type for the union, to keep the code clear: type NavType = DevNavType | NotDevNavType
like image 102
Nikos Paraskevopoulos Avatar answered Oct 09 '22 09:10

Nikos Paraskevopoulos