29

I want to declare a variable with two types via TypeScript, but the compiler gives me a type error.

interface IAnyPropObject { 
        [name: string]: any;
}
let a: IAnyPropObject | ((str: string) => any);
a.b = "bbbbbbbb"; /* type error */
a(""); /* type error */

I don't want to use any to declare. I just want to constrain the variable to be only these types. Because the code are so old and they are not TypeScript code.

7
  • 4
    A variable with two types..? Two?! So, what your saying is, that in TypeScript a variable can be a String and an Integer at the same time. How is this even possible? THIS IS MADNESS! Commented Jun 22, 2017 at 2:03
  • TS supports union type.I just want to constraint the variable by this way. Commented Jun 22, 2017 at 2:05
  • Sure that code should throw an error, you didn't initialise a so you cannot assign a property on it. Commented Jun 22, 2017 at 2:22
  • 3
    @rudy It's not male and female at the same time, it's saying it can accept both types, but it's only one at a time. Commented Jun 22, 2017 at 2:25
  • @Bergi OP is talking about a compilation error, not a runtime. Dies TypeScript fail compilation for using uninitialized variables? Haven't tested it Commented Jun 22, 2017 at 2:26

2 Answers 2

39

Brief explanation of Mixin vs Union types.

Union: Either this or that type, but not both.

interface A { [name: string]: any; }
interface B { (str: string): string; }
type UnionType = A | B;

Mixin: A mix of this and that type at the same time.

interface A { [name: string]: any; }
interface B { (str: string): string; }
type MixinType = A & B;

Your code would work if you use a Mixin type, if that is your intention. Variable a can have a mix of both types at the same time.

Sign up to request clarification or add additional context in comments.

2 Comments

To use the &, the OP would have to pass something that is of both types,that is, satisfies both interfaces; in this case, a function is an object so it would be almost true except that you can set a function property by brackets using a number, which shouldn't be allowed from the definition given by the OP. What kind of object could you possibly pass in that correctly implements both interfaces?
yeah.I can leave out 'if ...'
7

If you use an OR type, that doesn't mean your object has two types at the same time, you have to test it and use the correct type with casting inside of the test.

See https://www.typescriptlang.org/docs/handbook/advanced-types.html

interface IAnyPropObject { [name: string]: any; }
type MyFunc = (str: string) => any;
let a: IAnyPropObject | ((str: string) => any);
if (a instanceof Function) {
     (<MyFunc>a)("hi"); //passing a number will throw an error
} else {
    (<IAnyPropObject>a).b = 'bbbbbbbb';
}

You could also create a custom type guard, it's explained in the documentation I linked to, then you would not have to cast it. There's a lot more to be said, I just scratched the surface since I'm answering from my phone, read the doc for all the details.

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.