5

I would like to define a type that enforces each character be '1'|'0'

type Binary = '1'|'0'

this works, but only with a string length of 1. Is there any way to define the type as 1 or 0 repeating?

Also curious if there is a way to enforce length? This is the only thing I could come up with

type BinaryInput = `${Binary}${Binary}${Binary}${Binary}${Binary}`;
3
  • Conceptually this is a large union type (or infinite if you don't constrain length), but TS can only handle unions of ~100K members and pragmatically anything close will bog down the compiler and interact poorly with other types, so if you write BinaryLength<16> or BinaryLength<32> as a big union you will have a bad time. You can make a constraint that checks a candidate type, though, but this depends on your use case. What will you do with such a type? Have it as an input to a function? Could you show a minimal reproducible example of some uses? Commented Dec 3, 2021 at 14:10
  • 3
    Like, if you have a library that you expect developers to call with a string literal and you want to validate that it's a binary string literal of a set (or not set) length, you can do this. If you have some other use case please spell it out with examples otherwise I'll just spin my wheels thinking of possible workarounds for an unspecified use case (or, you know, look at something else for a while 😅) Commented Dec 3, 2021 at 14:31
  • 2
    What would be the benefit of having such a type? I only see one if you define a lot of binary constants in your code and want that to be typesafe. Otherwise you could simply use a string and implement the checking at runtime by encapsulating the string with a class. Commented Dec 3, 2021 at 16:33

2 Answers 2

2

If you just want type safety at the interfaces of your API, you can use a type that extends string and is impossible to obtain without assertion (I don't know what this is called, but I like the name "snowflake type"). Then use a type guard to validate the strings (or simply assert the type if you're sure and need the performance gain of skipping the runtime check).

TS Playground link

type Binary<N extends number = number> = string & {
  readonly BinaryStringLength: unique symbol;
  length: N;
};

class AssertionError extends Error {
  name = 'AssertionError';
}

function assertIsBinaryString <L extends number>(
  str: string,
  length?: L,
): asserts str is Binary<L> {
  if (typeof length === 'number' && str.length !== length) {
    throw new AssertionError('Binary string has invalid length');
  }

  for (const unit of str) {
    if (unit !== '0' && unit !== '1') {
      throw new AssertionError('Invalid character in binary string');
    }
  }
}


// Use:

function asDecimal (bStr: Binary): number {
  return parseInt(bStr, 2);
}

function byteAsChar (byte: Binary<8>): string {
  return new TextDecoder().decode(new Uint8Array([asDecimal(byte)]));
}

let str = '00100100';
// console.log(asDecimal(str)); // string not assignable to Binary
/*                       ^^^
                      Error 2345 */

assertIsBinaryString(str);
console.log(asDecimal(str)); // ok now => 36

// console.log(byteAsChar(str)); // Binary<number> not assignable to Binary<8> because number not assignable to 8
/*                        ^^^
                      Error 2345 */

assertIsBinaryString(str, 8);
console.log(byteAsChar(str)); // ok now => "$"
Sign up to request clarification or add additional context in comments.

1 Comment

Usually this is called branding.
0

Branded types is likely your best option.


Assuming you store binaries like a number e.g.

const myBinary = 0b1000;
typeof myBinary // 'number'

You can brand the primitive number type:

type Binary = number & { readonly __brand: unique symbol };

For a specific length:

type Binary<Length extends number> = number & { readonly __brand: unique symbol, length: Length }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.