Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Roadie
Jun 30, 2013
This is a Typescript question rather than a Javascript one exactly, but I figured it fits here.

Is there a way to import TS type definitions for a module, without actually for-real doing a module import?

For more context, I'm making a thing that wraps some different-implementation-per-browser functionality in a class based on core Node stuff, so I'd be really happy if I could do a class Something implements whatever.Thing and have the TS compiler complain about differences, but without actually doing a import whatever from 'whatever' (because, obviously, that's not going to exist in the browser).

Adbot
ADBOT LOVES YOU

Roadie
Jun 30, 2013

Skandranon posted:

Yep, just add /// <reference path="../typings/jquery.d.ts"/> to the top of your file. TypeScript will act as if the type definitions will be valid.

You can also add this to your list of compiled files to your TypeScript compiler, if you'd rather not put it in all your files.

VSCode will also automatically read all the .d.ts files in the folder and below that contains tsconfig.json, and use them for intellisense.

I actually already tried this out and it doesn't work. If it's a typings file with declare module "whatever" { ... }, just doing a <reference path> or (if it's an NPM module) <reference types> won't load anything in the whatever namespace without an import statement.

Roadie
Jun 30, 2013

Skandranon posted:

This is for d.ts files. If you are trying to load interfaces defined in an actual .ts file... won't go so well. You should separate out the interfaces to a d.ts file.

This seems really silly, since it means I'd have a definitions file that just repeats every interface name in the original module with an extends statement on each.

Roadie
Jun 30, 2013

Skandranon posted:

I don't think I understand your issue then, I'd need to see a more concrete example of your issue before I could offer a better answer?

Node has module X. I want to make module replace-X-in-the-browser, with all its stuff implementing interfaces from module X's definitions in @typings/node.

Roadie
Jun 30, 2013

The Fool posted:

For the sake of argument, what are some things that can be done to make this bit of code not a giant black hole of security risks?

Nothing. Anything that lets people run arbitrary command-line code will gently caress you.

What do you actually want to do with this?

Roadie
Jun 30, 2013

The Fool posted:

It's just a toy that isn't going to be run anywhere except my home lab. I do plan on putting a react app on top of this to select from a list of scripts in a folder, execute them, and display the results.

In this case, code the scripts into the server, hard match against them, and never accept a parameter that you can't pass with strict binding as a self-contained string (think: directly calling function via C-to-node interfaces).

code:
function scriptname1 (params) {
  let cats = params.cats

  if (typeof cats === 'string') {
    callExternalLibraryHere(cats)
  } else {
    doOtherThingHere()
  }

  // TODO: do the thing
  return 'Output goes here'
}

function scriptname2 () {
  // TODO: do the thing
  return 'Output goes here'
}

function scriptname3 () {
  // TODO: do the thing
  return 'Output goes here'
}

app.get('/scripts/:script', function (req, res) {
  let output

  if (req.params.script === 'scriptname1') {
    output = scriptname1({thing1: req.query.cats})
  }

  if (req.params.script === 'scriptname2') {
    output = scriptname2()
  }

  if (req.params.script === 'scriptname3') {
    output = scriptname3()
  }

  if (output) {
    res.send(output)
  }
})

Roadie
Jun 30, 2013

geeves posted:

#1 in java script: The Bad Parts or "DON'T loving DO THIS" - exec() (I realize this may be different in node, than in the browser - but until I know better/....)

It's worse. In the browser, it at least (probably) can't delete all your files and email illegal porn to all your relatives if you gently caress it up.

Roadie
Jun 30, 2013

mekkanare posted:

Alright, I'm mainly struggling with how to make it waiting until the query returns. I'll have to look into Promises some more first.

The key thing with Promises is that anything you return inside the Promise's callback gets supplied to the next thing in the chain (e.g. the callback you supply to whateverPromiseFunction.then()), unless what you return is a Promise itself, in which case it gets resolved first and the resolved value gets treated like it was the return value.

This lets you do stuff in an asynchronous way while still putting a specific flow on the overall process, so you can do stuff like...

code:
function somePromise () {
  return new Promise((resolve, reject) => {
    apiFunctionWithCallback(someApiValue => {
      resolve(someApiValue)
    })
  }).catch(err => {
    console.error('OH GOD EVERYTHING IS ON FIRE:', err)
  })
}

function returnsThing1 () {
  return somePromise.then(someApiValue => {
    return 'I love cats'
  }).catch(err => {
    console.error('OH GOD EVERYTHING IS ON FIRE:', err)
  })
}

function returnsThing2 () {
  return returnsThing1.then(iLoveCats => {
    return someOtherPromise('I love dogs')
  }).catch(err => {
    console.error('OH GOD EVERYTHING IS ON FIRE:', err)
  })
}

function returnsThing3 () {
  return returnsThing2.then(iLoveDogs => {
    return 'I love fish'
  }).catch(err => {
    console.error('OH GOD EVERYTHING IS ON FIRE:', err)
  })
}
...or...

code:
new Promise((resolve, reject) => {
  apiFunctionWithCallback(someApiValue => {
    resolve(someApiValue)
  })
}).then(someApiValue => {
  // do an operation here
  return 'I love cats'
}).then(iLoveCats => {
  // do an operation here
  return someOtherPromise('I love dogs')
}).then(iLoveDogs => {
  // do an operation here
  return 'I love fish'
}).catch(err => {
  console.error('OH GOD EVERYTHING IS ON FIRE:', err)
})
...and that way you can break out a bunch of stuff into individual Promises that each operate independently but that you can still chain together easily, without things getting nested ten levels deep like the classic callback hell style.

Roadie fucked around with this message at 09:32 on Jan 20, 2017

Roadie
Jun 30, 2013

Cugel the Clever posted:

Junior front-end dev here. I had two coworkers voice preference for relying on for loops over the higher order array methods like forEach, map, filter, and reduce. Ignoring browser compatibility entirely, where would people here come down on this? My own thinking is that there's no clarity lost in the higher order functions, and they more succinctly achieve their intended task. I'm self-taught, so had picked up the methods in Eloquent Javascript, which suggests them to have no substantial efficiency costs. No dog in this fight, just looking to broaden my understanding of the language.

Uses of map/filter/reduce are (if you use them right) almost all easier to re-understand in the future than a loop, and there's a performance difference but it's not one that actually matters unless you're processing huge amounts of data all the time.

forEach is pointless once you've got for-of syntax working, though, since forEach only got used in the first place because for-in syntax is broken for most uses.

Roadie
Jun 30, 2013

Thermopyle posted:

Ok, I'm wanting to do in Node what I do in Django. What's the most popular or best things for doing the main parts of Django in Node? That'd be templating, ORM, user management, form handling...the usual stuff you'd expect out of a batteries-included framework.

I'm not really expecting there to be one framework and that I'll have to glue together stuff, but maybe I'm wrong on that.

The closest you'll probably see is Ember.js, and even that's meant to be more like a Ruby on Rails thing where it maps frontend routes to backend stuff and you hook up your own choice of ORM, etc.

Strapi bundles an ORM and user management and other such stuff, but they're in "next version is almost ready" limbo at the moment.

Roadie
Jun 30, 2013

Thermopyle posted:

Thanks for the replies. Why the gently caress is node so popular on the backend if there aren't any good full-feature frameworks for it yet?

(and by popular I mean lots of results on job sites)

With Express & company it's extremely easy to get up and running for APIs and for the equivalent of Flask/Sinatra style "start small and keep adding features as you expand" sites.

Roadie
Jun 30, 2013

ROFLburger posted:

Just curious, why is this?

There was no real threading available for a long time, and even now you can only do it with libraries that work around it by including C code that gets compiled with node-gyp. This also means that the server frameworks like Express pretty much haven't touched the idea because they're trying to be platform-independent and there's nothing equivalent included in core Node.

Roadie
Jun 30, 2013

peepsalot posted:

I'm looking into websockets, right now I'm confused that there seems to be two different ways to send over WebSocket: Blob or ArrayBuffer? But you have to read both via a DataView anyways, or something? When would you choose one over the other?

Blobs are immutable, can have MIME types, and can be used as a source for URLs (image sources, file downloads, etc). ArrayBuffers are basically an array of ints that can be monkeyed with using appropriate TypedArrays or DataViews (usually using uint8 to access as an array of 8-bit bytes).

For most purposes you'll want to use ArrayBuffers internally (possibly with a helper lib like feross/buffer), and generate a Blob from that if you're specifically doing a file download thing or whatever at some point.

Roadie fucked around with this message at 01:59 on Feb 24, 2017

Roadie
Jun 30, 2013

Xom posted:

I'm working on http://www.cardery.org/ which uses dom-to-image to convert DOM elements to PNG. Something about the way dom-to-image inlines images causes Firefox to blank out images from file:///. If I reimplement this step myself, then Firefox lets the file:/// images through if they're in the same folder. (Chrome doesn't let them through in any case.) But if I don't wait for a tiny moment before continuing on to invoking dom-to-image, then the output still has blanks where the images were. If I do wait for a moment, such as by using lodash.defer, then I mostly don't get blanked. Naturally I would like to wait for as few milliseconds as I can get away with.

What I'm imagining, though I'm not familiar enough with web development to know for sure if it is possible, is that I set the handler, then <img src="Sigmund.png"> finishes loading, then I set the src to data:bLaHbLaHbLaH, then from the trigger from the original Sigmund.png tells me to continue on to invoke dom-to-image, even though it was the dataUrl that I intended to listen for. Admittedly, my concern here is somewhat academic, given that _.defer is enough of a wait most of the time.

What I don't really get is why you're jiggering around in-place with stuff that's in the visible output of the page. Even if dom-to-image requires a visible element, you could use "workspace" stuff positioned outside the viewport (e.g. position: absolute; left: -10000px type wrapper), append a new node for each conversion, and delete that specific node and add the result to the visible viewport in the result callback.

Edit: Wait, maybe now I think I get what you mean. Why make the image tags like that and then alter them after they're already in place? I don't really get why it's file source to data source, instead of waiting, generating a new Image() when you have the data URL, and adding that to the right node.

Roadie fucked around with this message at 07:02 on Feb 27, 2017

Roadie
Jun 30, 2013

Munkeymon posted:

dom-to-image uses an SVG feature that allows you to embed HTML into an SVG and I'm guessing there are protections around using that to hide access to file:// URLs. Sounds like a way around that is to replace every file:// URL with a data: URL with the same content before trying to make the SVG turduckin.

I've done a thing that waited for a bunch of images to load before and IIRC, I put a handler on all of their onload events and counted the handlers as they were created. Then each handler decremented the counter until it was zero which allowed the last one to run a callback, which would make the dom-to-image call in this case. Pretty sure the modern way would be to wrap all of that in a promise.

Right. What I mean is (now that I've got my head more wrapped around it), it'd be better to do that file url to data url step before even creating the DOM nodes that get run through dom-to-image.

code:
function createCardImage (fileUrl) {
    return new Promise(fileUrl => {
        // ... do conversion stuff
        resolve("data url here")
    }).then(dataUrl => {
        // ... create node
        resolve("node id here")
    }).then(nodeId => {
        // ... do dom-to-image stuff here
        resolve("image result here")
    })
}

createCardImage("whatever").then(imageResult => {
    // add image to visible page here
})

Roadie fucked around with this message at 19:46 on Feb 27, 2017

Roadie
Jun 30, 2013

TheFluff posted:

but I didn't like the promise idea of making async code look like it's synchronous either.
I don't really understand how promises are supposed to make something "look like it's synchronous". The whole point of the promise structure is that (barring use of async/await) you're for the most part just breaking everything down into the separate parts that are synchronous, with the asynchronous breakpoints between them being the resolving/rejecting of the promise. Async/await is just sugar over "the rest of this function is going to be in a then clause anyway".

TheFluff posted:

I can still change my mind though, so please tell me now about what kind of huge rear end traps I'm about to fall into.
Literally everyone but you is going to use promises, so every time you ever use any kind of other library with anything that's ever asynchronous you'll have write weird wrappers around everything.

Roadie fucked around with this message at 20:58 on Mar 13, 2017

Roadie
Jun 30, 2013

TheFluff posted:

e: really, I think what's making me suspicious is that I don't feel like I understand promises. There's really not much much to them at all, but there's something that unsettles me. Brains, man.

Probably the biggest weirdness to wrap your head around is that inside the function for a promise, you can return a value that gets passed in to the next then function, or you can return a Promise which gets evaluated before the next Promise in the chain does (which itself can return a Promise, which itself can return a Promise, which itself can...).

Some of the conceptual weirdness there goes away if you use async/await for that, since that makes "returns a value" and "returns a Promise that resolves to a value" syntactically identical except for the async decorator.

Roadie fucked around with this message at 18:49 on Mar 15, 2017

Roadie
Jun 30, 2013

ddiddles posted:

Jesus, that made the code that builds the movie list for the client so much cleaner.

code:
function movieList(moviesAndGenres) {
  return moviesAndGenres.movies.map((movie) => {
    return {
      title: movie.title,
      genre: movie.genre_ids.map((id) => { return moviesAndGenres.genres[id] })
    }
  });
}

You can also trim this down a little more:

code:
function movieList (moviesAndGenres) {
  return moviesAndGenres.movies.map(movie => ({
    title: movie.title,
    genre: movie.genre_ids.map(id => moviesAndGenres.genres[id])
  }))
}
or potentially

code:
const movieList = (moviesAndGenres) => moviesAndGenres.movies.map(movie => ({
    title: movie.title,
    genre: movie.genre_ids.map(id => moviesAndGenres.genres[id])
}))
Implicit returns are neat.

Roadie
Jun 30, 2013

ddiddles posted:

Oh, I thought .map() required a return statement in the callback?

Edit: On further reading, I was mixing that up with wanting to return something from the forEach callback. Nice, refactor upon refactor upon refactor.

If you have an arrow function without a block, the single statement in it is automatically returned. The ({}) syntax serves as a disambiguation for object literal vs function block.

Roadie
Jun 30, 2013

Knifegrab posted:

And just to clairfy what Roadie said because I myself am an example man:

code:
const things = items.map((item) => {
   return item.thing;
});
is equivalent to:

code:
const things = items.map((item) => item.thing);

If it's only a single parameter, you don't even need the parentheses around it.


code:
const things = items.map(item => item.thing)
code:
const things = items.map(item => ({a: item.a, b: item.b}))

Roadie fucked around with this message at 05:59 on Mar 20, 2017

Roadie
Jun 30, 2013

ROFLburger posted:

State changes should only ever be made through the setState method so that React can trigger updates and lifecycle methods.

This is the key thing. Other current frameworks do the details differently, but there's always some level of mushy workaround to be able to reliably detect that you changed X and have that trigger all your things that are watching for new values of X.

This isn't necessary for all uses, but it's generally just a lot easier to structure everything that way and then you can throw in "send a thing to the server when this value changes" or "handle JS-based resizes of components incorporating window size" without having to rebuild everything to accommodate it.

Roadie fucked around with this message at 21:48 on Mar 27, 2017

Roadie
Jun 30, 2013

Dominoes posted:

Love it. Now I've ran into a module I think I need (a react drag+drop to replace the jquery one I'm using) that appears to be usable by import or require. (Only an NPM package; no .js script) Any tips for getting import working? I looked through the create-react-app folder, but I don't know what I'm looking for re: imports. Same "Uncaught ReferenceError: exports is not defined" error as before.

You might have to do
code:
import * as whatevervar from 'modulename'
which is the workaround for modules that don't do the newer export structure.

Roadie
Jun 30, 2013

Dominoes posted:

Sweet, will have a look in the morning. Looks like the big change from your post is putting the child element construction within the parent, built from arguments, rather than passing the complete component as an arg. That might be the fix. Would still need a way to call that addGo method from outside; your example has it called from onClick, which doesn't trigger the issue I'm running into. In this case, Go is a component that has a table with its own children, a few buttons, and some headings; but I'm running into a general lack of understanding that these specifics shouldn't apply to.

Look up Redux and use that. Then you can make your components do exactly two things:

1) be a UI for stuff in the central store

2) be a source of actions for the central store

Your dynamic component weirdness becomes 1) data in the store to keep track of your current added components, 2) actions (possibly async) in the store to add or remove components, and 3) extra stuff in your component render functions to turn the stuff from the store into a rendered component.

Roadie
Jun 30, 2013
For automagical stuff, things like redux-pouchdb-plus are kind of cool. PouchDB itself is a JS database implementation that saves stuff local in the browser via IndexedDB or WebSQL and auto-syncs from a CouchDB instance on the web, and then the Redux integration automatically generates/updates your state from that, so the end result is that your state automatically populates from whatever CouchDB setup you have and you have to give minimal worry to handling offline usage, etc.

Newf posted:

by that, I mean, I hope, user authored React Components.

Do keep in mind that this is ultimately the same as letting random people put arbitrary code into your app.

Roadie fucked around with this message at 09:48 on Apr 16, 2017

Roadie
Jun 30, 2013
For people who find the accreted mess of native JS Maps, etc a bit much, I heartily recommend Immutable.js. Very efficient immutable collections, lazy evaluation options, and consistent methods and easy conversions across list/map/set/stack data structures.

Roadie
Jun 30, 2013

geeves posted:

Immutable.js and Collections.js are both really good. But I've been leaning towards Immutable. It helps that they both mirror Collections in Java

For me, the key thing about Immutable.js is that Seq is lazily processed but is directly compatible with everything else in the library. Really helps with gigantic data sets and the like.

Roadie
Jun 30, 2013

Dominoes posted:

Yeah - maybe it's due to using the redux-immutable combineReducers function. That example did have Immutable's combineReducers func vice the standard one.

You reminded me to try Immutable again... Got it working this time. The reducer function's cleaner now, but the .get syntax is pretty nasty, since I'm working with object (now immutable Map) nesting 3-4 layers deep. It's also confusing typescript.

JavaScript code:
warning.get('person').get('fields').get('first_name')

Use reslect or similar to split your getting up into logical chunks where possible.

Dominoes posted:

It's also confusing typescript.

Make sure to mark your Immutable.js collections and map functions with the types you want to use.
JavaScript code:
Map<number, string>()
List<string>().map((s): number => parseInt(s))
Also, use Immutable.js v4 (currently 4.0.0-rc.2, final release should be soon) so that types are preserved better (e.g. things don't turn into Iterators in the middle of a chain of functions) and so you can mark types for records:
JavaScript code:
interface Point {
  x: number
  y: number
}

const Point = Record<Point>({x: 0, y: 0}, 'Point')

function whatever (param1: Record.Instance<Point>): void {
  return
}

Roadie fucked around with this message at 20:10 on Apr 29, 2017

Roadie
Jun 30, 2013
Here's a question at the intersection of Typescript and Immutable.js, in case anybody is crazy enough to know the answer.

I have a Record-extending class Tom, with the attributes jones, ofFinland, and andJerry. I get in an arbitrary string, whichTom. How do I define a Typescript type guard function such that this:

code:
const isATom = (whichTom: string, tomInstance: Tom): boolean {
  // some kind of type guard shenanigans here?
  return tomInstance.has(whichTom)
}

if (isATom(whichTom, tomInstance)) {
  return tomInstance.get(whichTom)
}
doesn't give me a Argument of type "string" is not assignable to parameter of type '"jones" | "ofFinland" | "andJerry"'. Typescript error?

Roadie
Jun 30, 2013

Sedro posted:

I think you can do tomInstance.has(<keyof Tom>whichTom)

Oh, brilliant, keyof whatever was exactly what I was looking for.

For anyone else interested, you can do this with the following:

code:
import { Record } from 'immutable'

interface RecordTypeInterface {}

export default class RecordType extends Record<RecordTypeInterface>({}, 'RecordType') {
  has (key: string): key is keyof RecordTypeInterface {
    return super.has(key)
  }
}

Roadie
Jun 30, 2013

Dominoes posted:

Hey dudes. I've been trying to turn a pair of scripts into npm packages so I can share with others. I'm running into an import/export issues, where it's throwing 'uncaught TypeError: ... is not a function' or ...is not a constructor' for funcs and classes respectively, when calling a func or class constructor from a script where I import the module. Here's an example repo: the date lib I posted earlier

The NPM service doesn't build your packages for you. Your "main" needs to point to a compiled JS file, with "types" pointing at your original TS file. Set up a "prepublish" script that builds things and a .npmignore file that excludes everything that your .gitignore does except for the built JS file.

Roadie
Jun 30, 2013

Dominoes posted:

Hey dudes, another Q. Can you confirm that there's no way to overload operators in JS? this post seems pretty clean cut, but I'm wondering if there are any tricks. Ie, for the datetime library I'm working on, I'd like to define behaviour to add or subtract timedeltas. I could do it with syntax like this:

JavaScript code:
dateTypes.add(DateOnly(2016, 2, 3), TimeDelta(minutes=3))
but would prefer

JavaScript code:
DateOnly(2016, 2, 3) + TimeDelta(minutes=3)

Do it like this:

JavaScript code:
DateOnly(2016, 2, 3).add(TimeDelta({minutes: 3}))
Where DateOnly#add returns another DateOnly (or whatever), so then you can chain more methods onto it.

Dominoes posted:

I think I can't do the kwarg style either, so the delta would have to be TimeDelta(0, 3). Is that right?

See above. You can use an object for parameters, and if you're using ES6 or Typescript, automatically destructure it in the function definition:

JavaScript code:
class TimeDelta {
  constructor ({minutes = 0}) {
    console.log('minutes:', minutes)
  }
}

// or in Typescript
class TimeDelta {
  constructor ({minutes = 0}: {minutes: number}) {
    console.log('minutes:', minutes)
  }
}
If you really want to be fancy, you can support both:

code:
class TimeDelta {
  constructor (...args) {
    let hours = 0
    let minutes = 0

    if (typeof args[0] === 'number') {
      hours = args[0] || 0
      minutes = args[1] || 0
    } else {
      hours = args.hours || 0
      minutes = args.minutes || 0
    }

    console.log('hours:', minutes)
    console.log('minutes:', minutes)
  }
}

// or in Typescript
class TimeDelta {
  constructor (hours?: number, minutes?: number)
  constructor ({hours, minutes}: {hours: number, minutes: number})
  constructor (paramsOrHours?: number | {hours: number, minutes: number}, maybeMinutes?: number) {
    let hours = 0
    let minutes = 0

    if (typeof paramsOrHours === 'number') {
      hours = paramsOrHours || 0
      minutes = maybeMinutes || 0
    } else {
      hours = paramsOrHours.hours || 0
      minutes = paramsOrHours.minutes || 0
    }

    console.log('hours:', minutes)
    console.log('minutes:', minutes)
  }
}

Roadie
Jun 30, 2013

Dominoes posted:

Thanks dude! I'm going for funcs over methods when able for style reasons.

Don't. Everyone will hate you for doing it (and won't use the library), because chained methods is the style that literally everyone else uses.

Edit: When it doubt, use the general style of Immutable.js as a pattern to follow for data-manipulation libraries.

Dominoes posted:

Didn't know about multiple constructors either.

In Typescript, multiple method definitions is basically just sugar over whatever the last method definition is, in that it'll map your typings to whichever is appropriate for documentation/display purposes, but the last one needs to accommodate all of them at once.

Roadie fucked around with this message at 01:17 on May 30, 2017

Roadie
Jun 30, 2013

IAmKale posted:

So here's my question: How can I break up and organize my code into multiple files, but get tsc to output a single JavaScript file in basic ES5?

Use Webpack.

Roadie
Jun 30, 2013

Grump posted:

and Babel

You don't need Babel if it's an all-Typescript project. Just set the tsconfig.json to target ES5.

Roadie
Jun 30, 2013

porksmash posted:

How come pulling down a repo and running npm i modifies package-lock.json? I develop on two different computers and it's driving me crazy. I'll add a package on my laptop, commit package.json and package-lock.json, and then when I pull the change and npm i, I get a different package-lock.json. Doesn't this defeat the purpose? Am I misunderstanding why package-lock.json exists?

It sounds like you've got two different versions of npm 5.0.x. They're still fiddling with the fine details of the package-lock.json format.

Roadie
Jun 30, 2013

huhu posted:

Thanks for the replies.

New question. Is this article really the bare minimum to get Google Maps working with React? https://www.fullstackreact.com/articles/how-to-write-a-google-maps-react-component/ It feels like overkill. I'm trying to learn React with a project idea and I'm feeling no benefit yet of using it. I could probably build out my entire idea in plain JS/HTML/CSS with less code than that demo.

Keep in mind that a bunch of that article is just walking back and forth across the same things to incrementally add new features, and then 90% of what's actually built out is to make a super generic Google Maps component meant to be reused in any project you ever make rather than a one-off with specific uses.

Roadie
Jun 30, 2013
Use redux, do your request stuff in redux action creators via redux-pack, use reselect to bind your child components to the specific bits of the redux store being used.

Roadie
Jun 30, 2013
Simple, lovely monkey-patch version:

code:
String.prototype.containsOne = function (strs) {
  if (!(strs instanceof Array)) {
    return false
  }

  var matches = false
  strs.forEach(function (str) {
    if (this.indexOf(str) !== -1) {
      matches = true
    }
  })

  return matches
}

if (foobar.containsOne(['string1', 'string2', 'string3'])) {
  whatever()
}

Roadie
Jun 30, 2013
Also note that interfaces can be used to represent all kinds of complicated things.
code:
enum Something {
  First,
  Second,
  Third
}

interface Whatever {
  (): void // it's actually a function with other stuff added to it as properties

  // object structures
  property1: {
    nestedproperty: boolean
    othernestedproperty: number

    // allows "First", "Second", "Third"
    dynamicproperty: keyof typeof Something

    // allows "nestedproperty", "othernestedproperty", "dynamicproperty"
    anotherproperty: keyof Whatever['property1']
  }

  // an object that has fixed properties but also generic keys
  property2: {
    preset: boolean
    [key: string]: number
  }
}
And that's before you get into generics, which can do cool stuff.

code:
interface Thing<K> {
  [key: string]: K
}

const mapOfPoints: Thing<{x: number, y: number}> = {}

Adbot
ADBOT LOVES YOU

Roadie
Jun 30, 2013

Knifegrab posted:

I've got another odd question. I have an array that can contain a number of functions, but I cannot tell immediately what the function is.

so basically the array looks like this:

code:
let myArr = [funcA, funcB, funcC, funcB, funcC, funcA, funcA, funcA...];
The problem is I have no idea the order of the array or even if what I need is in there.

Bascially I want to iterate through the array and if the function is funcA, I want to call that function with my parameters. All of the functions take different parameters and do very different things. Sometimes an item in the array may not even be a function.

Obviously I know I can do typeOf to figure out if it is a function, but how do I tell if the function points to a specific function schema.

This becomes even more difficult because the function that is in the array is generated by a function that returns a new anonymized function so the pointer is going to be different each time.

Any ideas?

code:
const someFunction = function() { return }
someFunction.typeForComparisonPurposes = 'funcA'
Then put them into the array.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply