Typescript
  • Introducão
  • Primeiros Passos
    • Por que TypeScript
  • JavaScript
    • Igualdade
    • Referências
    • Null vs. Undefined
    • this
    • Closure
    • Number
    • Truthy
  • Futuro JavaScript Agora
    • Classes
      • Classes Emit
    • Arrow Functions
    • Rest Parameters
    • let
    • const
    • Destructuring
    • Spread Operator
    • for...of
    • Iterators
    • Template Strings
    • Promise
    • Generators
    • Async Await
  • Project
    • Compilation Context
      • tsconfig.json
      • Which Files?
    • Declaration Spaces
    • Modules
      • File Module Details
      • globals.d.ts
    • Namespaces
    • Dynamic Import Expressions
  • Node.js QuickStart
  • Browser QuickStart
  • TypeScript's Type System
    • JS Migration Guide
    • @types
    • Ambient Declarations
      • Declaration Files
      • Variables
    • Interfaces
    • Enums
    • lib.d.ts
    • Functions
    • Callable
    • Type Assertion
    • Freshness
    • Type Guard
    • Literal Types
    • Readonly
    • Generics
    • Type Inference
    • Type Compatibility
    • Never Type
    • Discriminated Unions
    • Index Signatures
    • Moving Types
    • Exception Handling
    • Mixins
  • JSX
    • React
    • Non React JSX
  • Options
    • noImplicitAny
    • strictNullChecks
  • Errors in TypeScript
    • Interpreting Errors
    • Common Errors
  • NPM
  • Testing
    • Jest
    • Cypress
  • Tools
    • Prettier
    • Husky
    • Changelog
  • TIPs
    • String Based Enums
    • Nominal Typing
    • Stateful Functions
    • Bind is Bad
    • Currying
    • Type Instantiation
    • Lazy Object Literal Initialization
    • Classes are Useful
    • Avoid Export Default
    • Limit Property Setters
    • outFile caution
    • JQuery tips
    • static constructors
    • singleton pattern
    • Function parameters
    • Build Toggles
    • Barrel
    • Create Arrays
    • Typesafe Event Emitter
  • StyleGuide
  • TypeScript Compiler Internals
    • Program
    • AST
      • TIP: Visit Children
      • TIP: SyntaxKind enum
      • Trivia
    • Scanner
    • Parser
      • Parser Functions
    • Binder
      • Binder Functions
      • Binder Declarations
      • Binder Container
      • Binder SymbolTable
      • Binder Error Reporting
    • Checker
      • Checker Diagnostics
      • Checker Error Reporting
    • Emitter
      • Emitter Functions
      • Emitter SourceMaps
    • Contributing
Powered by GitBook
On this page

Was this helpful?

  1. TIPs

Bind is Bad

PreviousStateful FunctionsNextCurrying

Last updated 5 years ago

Was this helpful?

This is the definition of bind in lib.d.ts:

bind(thisArg: any, ...argArray: any[]): any;

As you can see it returns any! That means that calling bind on a function will cause you to completely lose any type safety of the original function signature.

For example the following compiles:

function twoParams(a:number,b:number) {
    return a + b;
}
let curryOne = twoParams.bind(null,123);
curryOne(456); // Okay but is not type checked!
curryOne('456'); // Allowed because it wasn't type checked!

A better way to write it would be with a simple with an explicit type annotation:

function twoParams(a:number,b:number) {
    return a + b;
}
let curryOne = (x:number)=>twoParams(123,x);
curryOne(456); // Okay and type checked!
curryOne('456'); // Error!

But if you expect a curried function .

Class Members

Another common use is to use bind to ensure the correct value of this when passing around class functions. Don't do that!

The following demonstrates the fact that you lose parameter type safety if you use bind:

class Adder {
    constructor(public a: string) { }

    add(b: string): string {
        return this.a + b;
    }
}

function useAdd(add: (x: number) => number) {
    return add(456);
}

let adder = new Adder('mary had a little 🐑');
useAdd(adder.add.bind(adder)); // No compile error!
useAdd((x) => adder.add(x)); // Error: number is not assignable to string
class Adder {
    constructor(public a: string) { }

    // This function is now safe to pass around
    add = (b: string): string => {
        return this.a + b;
    }
}

Another alternative is to manually specify the type of the variable you are binding e.g.

const add: typeof adder.add = adder.add.bind(adder);

If you have a class member function that you expect to pass around, e.g one would write the same Adder class as:

arrow function
there is a better pattern for that
use an arrow function in the first place