7307

How to define global function in TypeScript?

Question:

I want to define a global function that is available everywhere, without the need to import the module when used.

This function aims to replace the safe navigation operator (?) available in C#. For the sake of readability, I don't want to prefix the function with a module name.

Global.d.ts:

declare function s<T>(someObject: T | null | undefined, defaultValue?: T | null | undefined) : T;

Global.tsx:

///<reference path="Global.d.ts" /> export function s<T>(object: T | null | undefined, defaultValue: T | null = null = {} as T) : T { if (typeof object === 'undefined' || object === null) return defaultValue as T; else return object; }

App.tsx (root TypeScript file):

import 'Global';

Other TSX file (method usage):

s(s(nullableVar).member).member; //Runtime error

This compiles fine, however, in the browser this throws 's is not a function'.

Answer1:

You're defining the type for the compiler, but not actually attaching it to the global namespace — window in the browser, global in node. Instead of exporting it from the module, attach it. For isomorphic use, use something like...

function s() { ... } // must cast as any to set property on window const _global = (window /* browser */ || global /* node */) as any _global.s = s

You can also ditch the .d.ts file and declare the type in the same file using declare global, e.g.

// we must force tsc to interpret this file as a module, resolves // "Augmentations for the global scope can only be directly nested in external modules or ambient module declarations." // error export {} declare global { function s<T>(someObject: T | null | undefined, defaultValue?: T | null | undefined) : T; } const _global = (window /* browser */ || global /* node */) as any _global.s = function<T>(object: T | null | undefined, defaultValue: T | null = null) : T { if (typeof object === 'undefined' || object === null) return defaultValue as T; else return object; }

Answer2:

global.ts(x) needs just a little tweak to be a valid "global module" <em>(a module with side effects only)</em>: remove the export keyword and add some code to augment the global object. You can also provide the global declaration in the same file and remove global.d.ts.

<pre class="lang-js prettyprint-override">function _s<T>(object: T | null, defaultValue: T = {} as T) : T { return object == null ? defaultValue : object as T; } // Global declaration declare var s: typeof _s; // Global scope augmentation var window = window || null; const _global = (window || global) as any; _global.s = _s;

To use it, just import the module once, for instance in App.tsx via a global import: import './global';.

Tested with mocha, chai, ts-node:

<pre class="lang-js prettyprint-override">import { expect } from 'chai'; import './global'; // To do once at app bootstrapping describe('global s()', () => { it('should replace null with empty object', () => { const result = s(null); expect(result).to.eql({}); }); it('should replace undefined with empty object', () => { const result = s(undefined); expect(result).to.eql({}); }); it('should replace null with the given default value', () => { const defVal = { def: 'val' }; const result = s(null, defVal); expect(result).to.eql({ def: 'val' }); }); it('should preserve defined object', () => { const object = { bar: 'a' }; const result = s(object); expect(result).to.eql(object); }); });

Recommend

  • Why isn't there a difference between the ceiling and floor operators in this example? (Haskell)
  • aggregate sql with a where clause
  • CombineReducers with Typescript returns error “Argument of type is not assignable to parameter of ty
  • Importing static JSON in create-react-app + typescript
  • Upgrade Cassandra Version Brisk
  • React.js code not recognized in TSX file (VS 2015 Update 1 RC)
  • Typescript Error: TS2339: Property 'span' does not exist on type 'JSX.IntrinsicElemen
  • “the type does not fulfill the required lifetime” when using a method in a thread
  • Will these ActiveXObject and XMLHttpRequest checks apply for any other browser than IE6?
  • Why “propdp” code snippet doesn't use the nameof operator for the name of the registered proper
  • How to map childs/parent class with petapoco?
  • Data Type of Columns in a List - R
  • How to write string.Contains(someText) in expression Tree
  • DependencyObject.AssociatedObject is always null
  • Pythons argparse default value doesn't work
  • when does setTimeout start executing in a inline
  • Detection of framework usage on Mac system?
  • runtime error when linking ffmpeg libraries in qt creator
  • How do I register classes by both interface and namespace with Windsor?
  • Ruby on Rails App deployed to heroku showing “We're sorry, but something went wrong”
  • Detecting null parameter in preprocessor macro
  • Memory error in python- how to use more memory
  • SetWindowsHookEx does not react on media keys
  • C# program and C++ DLL compiled for 32-bit system crash on 64-bit system
  • Sort List of Strings By Version
  • req.body is undefined - nodejs
  • output of program is not same as passed argument
  • Trying to switch camera back to front but getting exception
  • Symfony2: How to get request parameter
  • Akka Routing: Reply's send to router ends up as dead letters
  • Is there a mandatory requirement to switch app.yaml?
  • Unit Testing MVC Web Application in Visual Studio and Problem with QTAgent
  • Free memory of cv::Mat loaded using FileStorage API
  • Angular 2 constructor injection vs direct access
  • Trying to get generic when generic is not available
  • Django query for large number of relationships
  • Programmatically clearing map cache
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can I use `wmic` in a Windows PE script?
  • How to push additional view controllers onto NavigationController but keep the TabBar?